diff options
210 files changed, 4176 insertions, 1123 deletions
diff --git a/.clang-format b/.clang-format index 03af56d64062..d60d33c08f3f 100644 --- a/.clang-format +++ b/.clang-format @@ -9,5 +9,17 @@ CommentPragmas: NOLINT:.* ConstructorInitializerIndentWidth: 6 ContinuationIndentWidth: 8 IndentWidth: 4 +JavaImportGroups: +- android +- androidx +- com.android +- dalvik +- libcore +- com +- junit +- net +- org +- java +- javax PenaltyBreakBeforeFirstCallParameter: 100000 SpacesBeforeTrailingComments: 1 diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp index 98e4f4509b52..9366ff2d81a9 100644 --- a/apct-tests/perftests/core/Android.bp +++ b/apct-tests/perftests/core/Android.bp @@ -62,4 +62,10 @@ android_test { test_suites: ["device-tests"], certificate: "platform", + + errorprone: { + javacflags: [ + "-Xep:ReturnValueIgnored:WARN", + ], + }, } diff --git a/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java index 2ef68ca7bdb2..05a3e1201a00 100644 --- a/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java @@ -118,7 +118,7 @@ public class ReferencePerfTest { int got = count.get(); if (n != got) { throw new IllegalStateException( - String.format("Only %i of %i objects finalized?", got, n)); + String.format("Only %d of %d objects finalized?", got, n)); } } } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index d9fe30da2cb7..e0d1a30e7ced 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -569,7 +569,7 @@ public class JobSchedulerService extends com.android.server.SystemService public static final long DEFAULT_RUNTIME_MIN_EJ_GUARANTEE_MS = 3 * MINUTE_IN_MILLIS; @VisibleForTesting static final long DEFAULT_RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS = 5 * MINUTE_IN_MILLIS; - static final boolean DEFAULT_PERSIST_IN_SPLIT_FILES = false; + static final boolean DEFAULT_PERSIST_IN_SPLIT_FILES = true; private static final boolean DEFAULT_USE_TARE_POLICY = false; /** diff --git a/core/api/current.txt b/core/api/current.txt index f201d81c600c..6a875b83674c 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -91,6 +91,18 @@ package android { field public static final String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR"; field public static final String FACTORY_TEST = "android.permission.FACTORY_TEST"; field public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE"; + field public static final String FOREGROUND_SERVICE_CAMERA = "android.permission.FOREGROUND_SERVICE_CAMERA"; + field public static final String FOREGROUND_SERVICE_CONNECTED_DEVICE = "android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE"; + field public static final String FOREGROUND_SERVICE_DATA_SYNC = "android.permission.FOREGROUND_SERVICE_DATA_SYNC"; + field public static final String FOREGROUND_SERVICE_HEALTH = "android.permission.FOREGROUND_SERVICE_HEALTH"; + field public static final String FOREGROUND_SERVICE_LOCATION = "android.permission.FOREGROUND_SERVICE_LOCATION"; + field public static final String FOREGROUND_SERVICE_MEDIA_PLAYBACK = "android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"; + field public static final String FOREGROUND_SERVICE_MEDIA_PROJECTION = "android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"; + field public static final String FOREGROUND_SERVICE_MICROPHONE = "android.permission.FOREGROUND_SERVICE_MICROPHONE"; + field public static final String FOREGROUND_SERVICE_PHONE_CALL = "android.permission.FOREGROUND_SERVICE_PHONE_CALL"; + field public static final String FOREGROUND_SERVICE_REMOTE_MESSAGING = "android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING"; + field public static final String FOREGROUND_SERVICE_SPECIAL_USE = "android.permission.FOREGROUND_SERVICE_SPECIAL_USE"; + field public static final String FOREGROUND_SERVICE_SYSTEM_EXEMPTED = "android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED"; field public static final String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; field public static final String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED"; field public static final String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE"; @@ -6946,7 +6958,7 @@ package android.app { method public void onTrimMemory(int); method public boolean onUnbind(android.content.Intent); method public final void startForeground(int, android.app.Notification); - method public final void startForeground(int, @NonNull android.app.Notification, int); + method public final void startForeground(int, @NonNull android.app.Notification, @RequiresPermission int); method @Deprecated public final void stopForeground(boolean); method public final void stopForeground(int); method public final void stopSelf(); @@ -12195,6 +12207,7 @@ package android.content.pm { field public static final int PERMISSION_DENIED = -1; // 0xffffffff field public static final int PERMISSION_GRANTED = 0; // 0x0 field public static final String PROPERTY_MEDIA_CAPABILITIES = "android.media.PROPERTY_MEDIA_CAPABILITIES"; + field public static final String PROPERTY_SPECIAL_USE_FGS_SUBTYPE = "android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"; field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff field public static final int SIGNATURE_MATCH = 0; // 0x0 field public static final int SIGNATURE_NEITHER_SIGNED = 1; // 0x1 @@ -12408,16 +12421,20 @@ package android.content.pm { field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000 field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1 field public static final int FLAG_USE_APP_ZYGOTE = 8; // 0x8 - field public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40 - field public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10 - field public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1 - field public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10 + field @Deprecated @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_LOCATION}, anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8 field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff - field public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 2; // 0x2 - field public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION = 32; // 0x20 - field public static final int FOREGROUND_SERVICE_TYPE_MICROPHONE = 128; // 0x80 - field public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; // 0x0 - field public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4; // 0x4 + field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 2; // 0x2 + field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION = 32; // 0x20 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_MICROPHONE}, anyOf={android.Manifest.permission.CAPTURE_AUDIO_OUTPUT, android.Manifest.permission.RECORD_AUDIO}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_MICROPHONE = 128; // 0x80 + field @Deprecated public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; // 0x0 + field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL}, anyOf={android.Manifest.permission.MANAGE_OWN_CALLS}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4; // 0x4 + field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING = 512; // 0x200 + field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_SPECIAL_USE = 1073741824; // 0x40000000 + field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED = 1024; // 0x400 field public int flags; field public String permission; } @@ -41896,6 +41913,7 @@ package android.telephony { field public static final String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool"; field public static final String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int"; field public static final String KEY_VONR_ENABLED_BOOL = "vonr_enabled_bool"; + field public static final String KEY_VONR_ON_BY_DEFAULT_BOOL = "vonr_on_by_default_bool"; field public static final String KEY_VONR_SETTING_VISIBILITY_BOOL = "vonr_setting_visibility_bool"; field public static final String KEY_VT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_RTT_CALL_BOOL = "vt_upgrade_supported_for_downgraded_rtt_call"; field public static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 4eeb42f70f35..ce1eff143185 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -7156,6 +7156,7 @@ package android.media.tv.tuner { public class Tuner implements java.lang.AutoCloseable { ctor @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public Tuner(@NonNull android.content.Context, @Nullable String, int); + method public int applyFrontend(@NonNull android.media.tv.tuner.frontend.FrontendInfo); method public int cancelScanning(); method public int cancelTuning(); method public void clearOnTuneEventListener(); @@ -7186,7 +7187,6 @@ package android.media.tv.tuner { method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_SHARED_FILTER) public static android.media.tv.tuner.filter.SharedFilter openSharedFilter(@NonNull android.content.Context, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.filter.SharedFilterCallback); method @Nullable public android.media.tv.tuner.filter.TimeFilter openTimeFilter(); method public int removeOutputPid(@IntRange(from=0) int); - method public int requestFrontendById(int); method public int scan(@NonNull android.media.tv.tuner.frontend.FrontendSettings, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.ScanCallback); method public int setLnaEnabled(boolean); method public int setMaxNumberOfFrontends(int, @IntRange(from=0) int); @@ -9969,9 +9969,10 @@ package android.os { method public boolean isCloneProfile(); method public boolean isCredentialSharableWithParent(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isGuestUser(); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isMainUser(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int); method public boolean isMediaSharedWithParent(); - method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser(); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser(); method public static boolean isRemoveResultSuccessful(int); method public boolean isRestrictedProfile(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public boolean isRestrictedProfile(@NonNull android.os.UserHandle); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index d1c1a17558d4..3fee610943ba 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -905,6 +905,7 @@ package android.content.pm { method public boolean isFull(); method public boolean isGuest(); method public boolean isInitialized(); + method public boolean isMain(); method public boolean isManagedProfile(); method public boolean isPrimary(); method public boolean isProfile(); @@ -923,6 +924,7 @@ package android.content.pm { field public static final int FLAG_FULL = 1024; // 0x400 field @Deprecated public static final int FLAG_GUEST = 4; // 0x4 field public static final int FLAG_INITIALIZED = 16; // 0x10 + field public static final int FLAG_MAIN = 16384; // 0x4000 field @Deprecated public static final int FLAG_MANAGED_PROFILE = 32; // 0x20 field public static final int FLAG_PRIMARY = 1; // 0x1 field public static final int FLAG_PROFILE = 4096; // 0x1000 diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 0f4644c63b8d..1b3282e752f4 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1398,9 +1398,18 @@ public class AppOpsManager { */ public static final int OP_READ_WRITE_HEALTH_DATA = AppProtoEnums.APP_OP_READ_WRITE_HEALTH_DATA; + /** + * Use foreground service with the type + * {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SPECIAL_USE}. + * + * @hide + */ + public static final int OP_FOREGROUND_SERVICE_SPECIAL_USE = + AppProtoEnums.APP_OP_FOREGROUND_SERVICE_SPECIAL_USE; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int _NUM_OP = 127; + public static final int _NUM_OP = 128; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -1930,6 +1939,14 @@ public class AppOpsManager { public static final String OPSTR_SYSTEM_EXEMPT_FROM_FORCED_APP_STANDBY = "android:system_exempt_from_forced_app_standby"; + /** + * Start a foreground service with the type "specialUse". + * + * @hide + */ + public static final String OPSTR_FOREGROUND_SERVICE_SPECIAL_USE = + "android:foreground_service_special_use"; + /** {@link #sAppOpsToNote} not initialized yet for this op */ private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0; /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */ @@ -2026,6 +2043,7 @@ public class AppOpsManager { OP_TURN_SCREEN_ON, OP_RUN_LONG_JOBS, OP_READ_MEDIA_VISUAL_USER_SELECTED, + OP_FOREGROUND_SERVICE_SPECIAL_USE, }; static final AppOpInfo[] sAppOpInfos = new AppOpInfo[]{ @@ -2419,7 +2437,10 @@ public class AppOpsManager { OPSTR_SYSTEM_EXEMPT_FROM_FORCED_APP_STANDBY, "SYSTEM_EXEMPT_FROM_FORCED_APP_STANDBY").build(), new AppOpInfo.Builder(OP_READ_WRITE_HEALTH_DATA, OPSTR_READ_WRITE_HEALTH_DATA, - "READ_WRITE_HEALTH_DATA").setDefaultMode(AppOpsManager.MODE_ALLOWED).build() + "READ_WRITE_HEALTH_DATA").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), + new AppOpInfo.Builder(OP_FOREGROUND_SERVICE_SPECIAL_USE, + OPSTR_FOREGROUND_SERVICE_SPECIAL_USE, "FOREGROUND_SERVICE_SPECIAL_USE") + .setPermission(Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE).build(), }; // The number of longs needed to form a full bitmask of app ops @@ -8486,8 +8507,9 @@ public class AppOpsManager { */ public int startProxyOpNoThrow(int op, @NonNull AttributionSource attributionSource, @Nullable String message, boolean skipProxyOperation) { - return startProxyOpNoThrow(op, attributionSource, message, skipProxyOperation, - ATTRIBUTION_FLAGS_NONE, ATTRIBUTION_FLAGS_NONE, ATTRIBUTION_CHAIN_ID_NONE); + return startProxyOpNoThrow(attributionSource.getToken(), op, attributionSource, message, + skipProxyOperation, ATTRIBUTION_FLAGS_NONE, ATTRIBUTION_FLAGS_NONE, + ATTRIBUTION_CHAIN_ID_NONE); } /** @@ -8499,7 +8521,8 @@ public class AppOpsManager { * * @hide */ - public int startProxyOpNoThrow(int op, @NonNull AttributionSource attributionSource, + public int startProxyOpNoThrow(@NonNull IBinder clientId, int op, + @NonNull AttributionSource attributionSource, @Nullable String message, boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags, int attributionChainId) { @@ -8517,7 +8540,7 @@ public class AppOpsManager { } } - SyncNotedAppOp syncOp = mService.startProxyOperation(op, + SyncNotedAppOp syncOp = mService.startProxyOperation(clientId, op, attributionSource, false, collectionMode == COLLECT_ASYNC, message, shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); @@ -8615,9 +8638,10 @@ public class AppOpsManager { */ public void finishProxyOp(@NonNull String op, int proxiedUid, @NonNull String proxiedPackageName, @Nullable String proxiedAttributionTag) { - finishProxyOp(op, new AttributionSource(mContext.getAttributionSource(), + IBinder token = mContext.getAttributionSource().getToken(); + finishProxyOp(token, op, new AttributionSource(mContext.getAttributionSource(), new AttributionSource(proxiedUid, proxiedPackageName, proxiedAttributionTag, - mContext.getAttributionSource().getToken())), /*skipProxyOperation*/ false); + token)), /*skipProxyOperation*/ false); } /** @@ -8632,10 +8656,11 @@ public class AppOpsManager { * * @hide */ - public void finishProxyOp(@NonNull String op, @NonNull AttributionSource attributionSource, - boolean skipProxyOperation) { + public void finishProxyOp(@NonNull IBinder clientId, @NonNull String op, + @NonNull AttributionSource attributionSource, boolean skipProxyOperation) { try { - mService.finishProxyOperation(strOpToOp(op), attributionSource, skipProxyOperation); + mService.finishProxyOperation(clientId, strOpToOp(op), attributionSource, + skipProxyOperation); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index 4d6e4aedba66..43023fe9c2ab 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -26,13 +26,11 @@ import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.app.IAppOpsCallback; -import com.android.internal.util.function.DecFunction; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuintConsumer; import com.android.internal.util.function.QuintFunction; -import com.android.internal.util.function.TriFunction; import com.android.internal.util.function.UndecFunction; /** @@ -135,6 +133,7 @@ public abstract class AppOpsManagerInternal { /** * Allows overriding start proxy operation behavior. * + * @param clientId The client calling start, represented by an IBinder * @param code The op code to start. * @param attributionSource The permission identity of the caller. * @param startIfModeDefault Whether to start the op of the mode is default. @@ -148,11 +147,12 @@ public abstract class AppOpsManagerInternal { * @param superImpl The super implementation. * @return The app op note result. */ - SyncNotedAppOp startProxyOperation(int code, @NonNull AttributionSource attributionSource, - boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, - boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags - int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags, - int attributionChainId, @NonNull DecFunction<Integer, AttributionSource, Boolean, + SyncNotedAppOp startProxyOperation(@NonNull IBinder clientId, int code, + @NonNull AttributionSource attributionSource, boolean startIfModeDefault, + boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, + boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, + @AttributionFlags int proxiedAttributionFlags, int attributionChainId, + @NonNull UndecFunction<IBinder, Integer, AttributionSource, Boolean, Boolean, String, Boolean, Boolean, Integer, Integer, Integer, SyncNotedAppOp> superImpl); @@ -176,10 +176,15 @@ public abstract class AppOpsManagerInternal { * * @param code The op code to finish. * @param attributionSource The permission identity of the caller. + * @param skipProxyOperation Whether to skip the proxy in the proxy/proxied operation + * @param clientId The client calling finishProxyOperation + * @param superImpl The "standard" implementation to potentially call */ - void finishProxyOperation(int code, @NonNull AttributionSource attributionSource, + void finishProxyOperation(@NonNull IBinder clientId, int code, + @NonNull AttributionSource attributionSource, boolean skipProxyOperation, - @NonNull TriFunction<Integer, AttributionSource, Boolean, Void> superImpl); + @NonNull QuadFunction<IBinder, Integer, AttributionSource, Boolean, + Void> superImpl); } /** diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 10cdf5315b55..042bdd7e2ed5 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1814,12 +1814,6 @@ class ContextImpl extends Context { } } try { - ActivityThread thread = ActivityThread.currentActivityThread(); - Instrumentation instrumentation = thread.getInstrumentation(); - if (instrumentation.isInstrumenting() - && ((flags & Context.RECEIVER_NOT_EXPORTED) == 0)) { - flags = flags | Context.RECEIVER_EXPORTED; - } final Intent intent = ActivityManager.getService().registerReceiverWithFeature( mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId, diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java new file mode 100644 index 000000000000..eccc5631d86a --- /dev/null +++ b/core/java/android/app/ForegroundServiceTypePolicy.java @@ -0,0 +1,1033 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.app.AppOpsManager.MODE_FOREGROUND; +import static android.content.pm.PackageManager.PERMISSION_DENIED; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_HEALTH; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED; + +import android.Manifest; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.app.compat.CompatChanges; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; +import android.compat.annotation.EnabledAfter; +import android.compat.annotation.Overridable; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; +import android.content.pm.ServiceInfo.ForegroundServiceType; +import android.hardware.usb.UsbAccessory; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbManager; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.ArraySet; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.compat.CompatibilityChangeConfig; +import com.android.internal.compat.IPlatformCompat; +import com.android.internal.util.ArrayUtils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.HashMap; +import java.util.Optional; + +/** + * This class enforces the policies around the foreground service types. + * + * @hide + */ +public abstract class ForegroundServiceTypePolicy { + static final String TAG = "ForegroundServiceTypePolicy"; + static final boolean DEBUG_FOREGROUND_SERVICE_TYPE_POLICY = false; + + /** + * The FGS type enforcement: + * deprecating the {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}. + * + * <p>Starting a FGS with this type (equivalent of no type) from apps with + * targetSdkVersion {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later will + * result in a warning in the log.</p> + * + * @hide + */ + @ChangeId + @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU) + @Overridable + public static final long FGS_TYPE_NONE_DEPRECATION_CHANGE_ID = 255042465L; + + /** + * The FGS type enforcement: + * disabling the {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}. + * + * <p>Starting a FGS with this type (equivalent of no type) from apps with + * targetSdkVersion {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later will + * result in an exception.</p> + * + * @hide + */ + // TODO (b/254661666): Change to @EnabledAfter(T) + @ChangeId + @Disabled + @Overridable + public static final long FGS_TYPE_NONE_DISABLED_CHANGE_ID = 255038118L; + + /** + * The FGS type enforcement: + * deprecating the {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_DATA_SYNC}. + * + * <p>Starting a FGS with this type from apps with targetSdkVersion + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later will + * result in a warning in the log.</p> + * + * @hide + */ + @ChangeId + @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU) + @Overridable + public static final long FGS_TYPE_DATA_SYNC_DEPRECATION_CHANGE_ID = 255039210L; + + /** + * The FGS type enforcement: + * disabling the {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_DATA_SYNC}. + * + * <p>Starting a FGS with this type from apps with targetSdkVersion + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later will + * result in an exception.</p> + * + * @hide + */ + // TODO (b/254661666): Change to @EnabledSince(U) in next OS release + @ChangeId + @Disabled + @Overridable + public static final long FGS_TYPE_DATA_SYNC_DISABLED_CHANGE_ID = 255659651L; + + /** + * The FGS type enforcement: Starting a FGS from apps with targetSdkVersion + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later but without the required + * permissions associated with the FGS type will result in a SecurityException. + * + * @hide + */ + // TODO (b/254661666): Change to @EnabledAfter(T) + @ChangeId + @Disabled + @Overridable + public static final long FGS_TYPE_PERMISSION_CHANGE_ID = 254662522L; + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_NONE = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_NONE, + FGS_TYPE_NONE_DEPRECATION_CHANGE_ID, + FGS_TYPE_NONE_DISABLED_CHANGE_ID, + null, + null + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_DATA_SYNC}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_DATA_SYNC = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_DATA_SYNC, + FGS_TYPE_DATA_SYNC_DEPRECATION_CHANGE_ID, + FGS_TYPE_DATA_SYNC_DISABLED_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC) + }, true), + null + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_MEDIA_PLAYBACK = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK) + }, true), + null + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_PHONE_CALL}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_PHONE_CALL = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_PHONE_CALL, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL) + }, true), + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.MANAGE_OWN_CALLS) + }, false) + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_LOCATION}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_LOCATION = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_LOCATION, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_LOCATION) + }, true), + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.ACCESS_COARSE_LOCATION), + new RegularPermission(Manifest.permission.ACCESS_FINE_LOCATION), + }, false) + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_CONNECTED_DEVICE = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE) + }, true), + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.BLUETOOTH_CONNECT), + new RegularPermission(Manifest.permission.CHANGE_NETWORK_STATE), + new RegularPermission(Manifest.permission.CHANGE_WIFI_STATE), + new RegularPermission(Manifest.permission.CHANGE_WIFI_MULTICAST_STATE), + new RegularPermission(Manifest.permission.NFC), + new RegularPermission(Manifest.permission.TRANSMIT_IR), + new UsbDevicePermission(), + new UsbAccessoryPermission(), + }, false) + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_MEDIA_PROJECTION = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION) + }, true), + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.CAPTURE_VIDEO_OUTPUT), + new AppOpPermission(AppOpsManager.OP_PROJECT_MEDIA) + }, false) + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_CAMERA}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_CAMERA = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_CAMERA, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_CAMERA) + }, true), + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.CAMERA), + new RegularPermission(Manifest.permission.SYSTEM_CAMERA), + }, false) + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MICROPHONE}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_MICROPHONE = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_MICROPHONE, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_MICROPHONE) + }, true), + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD), + new RegularPermission(Manifest.permission.CAPTURE_AUDIO_OUTPUT), + new RegularPermission(Manifest.permission.CAPTURE_MEDIA_OUTPUT), + new RegularPermission(Manifest.permission.CAPTURE_TUNER_AUDIO_INPUT), + new RegularPermission(Manifest.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT), + new RegularPermission(Manifest.permission.RECORD_AUDIO), + }, false) + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_HEALTH}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_HEALTH = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_HEALTH, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_HEALTH) + }, true), + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.ACTIVITY_RECOGNITION), + new RegularPermission(Manifest.permission.BODY_SENSORS), + new RegularPermission(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS), + }, false) + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_REMOTE_MESSAGING = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING) + }, true), + null + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_SYSTEM_EXEMPTED = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED) + }, true), + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.SCHEDULE_EXACT_ALARM), + new RegularPermission(Manifest.permission.USE_EXACT_ALARM), + new AppOpPermission(AppOpsManager.OP_ACTIVATE_VPN), + new AppOpPermission(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN), + }, false) + ); + + /** + * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SPECIAL_USE}. + * + * @hide + */ + public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_SPECIAL_USE = + new ForegroundServiceTypePolicyInfo( + FOREGROUND_SERVICE_TYPE_SPECIAL_USE, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID, + new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] { + new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE) + }, true), + null + ); + + /** + * Foreground service policy check result code: this one is not actually being used. + * + * @hide + */ + public static final int FGS_TYPE_POLICY_CHECK_UNKNOWN = + AppProtoEnums.FGS_TYPE_POLICY_CHECK_UNKNOWN; + + /** + * Foreground service policy check result code: okay to go. + * + * @hide + */ + public static final int FGS_TYPE_POLICY_CHECK_OK = + AppProtoEnums.FGS_TYPE_POLICY_CHECK_OK; + + /** + * Foreground service policy check result code: this foreground service type is deprecated. + * + * @hide + */ + public static final int FGS_TYPE_POLICY_CHECK_DEPRECATED = + AppProtoEnums.FGS_TYPE_POLICY_CHECK_DEPRECATED; + + /** + * Foreground service policy check result code: this foreground service type is disabled. + * + * @hide + */ + public static final int FGS_TYPE_POLICY_CHECK_DISABLED = + AppProtoEnums.FGS_TYPE_POLICY_CHECK_DISABLED; + + /** + * Foreground service policy check result code: the caller doesn't have permission to start + * foreground service with this type, but the policy is permissive. + * + * @hide + */ + public static final int FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_PERMISSIVE = + AppProtoEnums.FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_PERMISSIVE; + + /** + * Foreground service policy check result code: the caller doesn't have permission to start + * foreground service with this type, and the policy is enforced. + * + * @hide + */ + public static final int FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_ENFORCED = + AppProtoEnums.FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_ENFORCED; + + /** + * @hide + */ + @IntDef(flag = true, prefix = { "FGS_TYPE_POLICY_CHECK_" }, value = { + FGS_TYPE_POLICY_CHECK_UNKNOWN, + FGS_TYPE_POLICY_CHECK_OK, + FGS_TYPE_POLICY_CHECK_DEPRECATED, + FGS_TYPE_POLICY_CHECK_DISABLED, + FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_PERMISSIVE, + FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_ENFORCED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ForegroundServicePolicyCheckCode{} + + /** + * @return The policy info for the given type. + */ + @NonNull + public abstract ForegroundServiceTypePolicyInfo getForegroundServiceTypePolicyInfo( + @ForegroundServiceType int type, @ForegroundServiceType int defaultToType); + + /** + * Run check on the foreground service type policy for the given uid/pid + * + * @hide + */ + @ForegroundServicePolicyCheckCode + public abstract int checkForegroundServiceTypePolicy(@NonNull Context context, + @NonNull String packageName, int callerUid, int callerPid, boolean allowWhileInUse, + @NonNull ForegroundServiceTypePolicyInfo policy); + + @GuardedBy("sLock") + private static ForegroundServiceTypePolicy sDefaultForegroundServiceTypePolicy = null; + + private static final Object sLock = new Object(); + + /** + * Return the default policy for FGS type. + */ + public static @NonNull ForegroundServiceTypePolicy getDefaultPolicy() { + synchronized (sLock) { + if (sDefaultForegroundServiceTypePolicy == null) { + sDefaultForegroundServiceTypePolicy = new DefaultForegroundServiceTypePolicy(); + } + return sDefaultForegroundServiceTypePolicy; + } + } + + /** + * Constructor. + * + * @hide + */ + public ForegroundServiceTypePolicy() { + } + + /** + * This class represents the policy for a specific FGS service type. + * + * @hide + */ + public static final class ForegroundServiceTypePolicyInfo { + /** + * The foreground service type. + */ + final @ForegroundServiceType int mType; + + /** + * The change id to tell if this FGS type is deprecated. + * + * <p>A 0 indicates it's not deprecated.</p> + */ + final long mDeprecationChangeId; + + /** + * The change id to tell if this FGS type is disabled. + * + * <p>A 0 indicates it's not disabled.</p> + */ + final long mDisabledChangeId; + + /** + * The required permissions to start a foreground with this type, all of them + * MUST have been granted. + */ + final @Nullable ForegroundServiceTypePermissions mAllOfPermissions; + + /** + * The required permissions to start a foreground with this type, any one of them + * being granted is sufficient. + */ + final @Nullable ForegroundServiceTypePermissions mAnyOfPermissions; + + /** + * A customized check for the permissions. + */ + @Nullable ForegroundServiceTypePermission mCustomPermission; + + /** + * Not a real change id, but a place holder. + */ + private static final long INVALID_CHANGE_ID = 0L; + + /** + * @return {@code true} if the given change id is valid. + */ + private static boolean isValidChangeId(long changeId) { + return changeId != INVALID_CHANGE_ID; + } + + /** + * Construct a new instance. + * + * @hide + */ + public ForegroundServiceTypePolicyInfo(@ForegroundServiceType int type, + long deprecationChangeId, long disabledChangeId, + @Nullable ForegroundServiceTypePermissions allOfPermissions, + @Nullable ForegroundServiceTypePermissions anyOfPermissions) { + mType = type; + mDeprecationChangeId = deprecationChangeId; + mDisabledChangeId = disabledChangeId; + mAllOfPermissions = allOfPermissions; + mAnyOfPermissions = anyOfPermissions; + } + + /** + * @return The foreground service type. + */ + @ForegroundServiceType + public int getForegroundServiceType() { + return mType; + } + + @Override + public String toString() { + final StringBuilder sb = toPermissionString(new StringBuilder()); + sb.append("type=0x"); + sb.append(Integer.toHexString(mType)); + sb.append(" deprecationChangeId="); + sb.append(mDeprecationChangeId); + sb.append(" disabledChangeId="); + sb.append(mDisabledChangeId); + sb.append(" customPermission="); + sb.append(mCustomPermission); + return sb.toString(); + } + + /** + * @return The required permissions. + */ + public String toPermissionString() { + return toPermissionString(new StringBuilder()).toString(); + } + + private StringBuilder toPermissionString(StringBuilder sb) { + if (mAllOfPermissions != null) { + sb.append("all of the permissions "); + sb.append(mAllOfPermissions.toString()); + sb.append(' '); + } + if (mAnyOfPermissions != null) { + sb.append("any of the permissions "); + sb.append(mAnyOfPermissions.toString()); + sb.append(' '); + } + return sb; + } + + /** + * @hide + */ + public void setCustomPermission( + @Nullable ForegroundServiceTypePermission customPermission) { + mCustomPermission = customPermission; + } + + /** + * @return The name of the permissions which are all required. + * It may contain app op names. + * + * For test only. + */ + public @NonNull Optional<String[]> getRequiredAllOfPermissionsForTest() { + if (mAllOfPermissions == null) { + return Optional.empty(); + } + return Optional.of(mAllOfPermissions.toStringArray()); + } + + /** + * @return The name of the permissions where any of the is granted is sufficient. + * It may contain app op names. + * + * For test only. + */ + public @NonNull Optional<String[]> getRequiredAnyOfPermissionsForTest() { + if (mAnyOfPermissions == null) { + return Optional.empty(); + } + return Optional.of(mAnyOfPermissions.toStringArray()); + } + + /** + * Whether or not this type is disabled. + */ + @SuppressLint("AndroidFrameworkRequiresPermission") + public boolean isTypeDisabled(int callerUid) { + return isValidChangeId(mDisabledChangeId) + && CompatChanges.isChangeEnabled(mDisabledChangeId, callerUid); + } + + /** + * Override the type disabling change Id. + * + * For test only. + */ + public void setTypeDisabledForTest(boolean disabled, @NonNull String packageName) + throws RemoteException { + overrideChangeIdForTest(mDisabledChangeId, disabled, packageName); + } + + /** + * clear the type disabling change Id. + * + * For test only. + */ + public void clearTypeDisabledForTest(@NonNull String packageName) throws RemoteException { + clearOverrideForTest(mDisabledChangeId, packageName); + } + + @SuppressLint("AndroidFrameworkRequiresPermission") + boolean isTypeDeprecated(int callerUid) { + return isValidChangeId(mDeprecationChangeId) + && CompatChanges.isChangeEnabled(mDeprecationChangeId, callerUid); + } + + private void overrideChangeIdForTest(long changeId, boolean enable, String packageName) + throws RemoteException { + if (!isValidChangeId(changeId)) { + return; + } + final ArraySet<Long> enabled = new ArraySet<>(); + final ArraySet<Long> disabled = new ArraySet<>(); + if (enable) { + enabled.add(changeId); + } else { + disabled.add(changeId); + } + final CompatibilityChangeConfig overrides = new CompatibilityChangeConfig( + new Compatibility.ChangeConfig(enabled, disabled)); + IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( + ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); + platformCompat.setOverridesForTest(overrides, packageName); + } + + private void clearOverrideForTest(long changeId, @NonNull String packageName) + throws RemoteException { + IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( + ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); + platformCompat.clearOverrideForTest(changeId, packageName); + } + } + + /** + * This represents the set of permissions that's going to be required + * for a specific service type. + * + * @hide + */ + public static class ForegroundServiceTypePermissions { + /** + * The set of the permissions to be required. + */ + final @NonNull ForegroundServiceTypePermission[] mPermissions; + + /** + * Are we requiring all of the permissions to be granted or any of them. + */ + final boolean mAllOf; + + /** + * Constructor. + */ + public ForegroundServiceTypePermissions( + @NonNull ForegroundServiceTypePermission[] permissions, boolean allOf) { + mPermissions = permissions; + mAllOf = allOf; + } + + /** + * Check the permissions. + */ + @PackageManager.PermissionResult + public int checkPermissions(@NonNull Context context, int callerUid, int callerPid, + @NonNull String packageName, boolean allowWhileInUse) { + if (mAllOf) { + for (ForegroundServiceTypePermission perm : mPermissions) { + final int result = perm.checkPermission(context, callerUid, callerPid, + packageName, allowWhileInUse); + if (result != PERMISSION_GRANTED) { + return PERMISSION_DENIED; + } + } + return PERMISSION_GRANTED; + } else { + boolean anyOfGranted = false; + for (ForegroundServiceTypePermission perm : mPermissions) { + final int result = perm.checkPermission(context, callerUid, callerPid, + packageName, allowWhileInUse); + if (result == PERMISSION_GRANTED) { + anyOfGranted = true; + break; + } + } + return anyOfGranted ? PERMISSION_GRANTED : PERMISSION_DENIED; + } + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("allOf="); + sb.append(mAllOf); + sb.append(' '); + sb.append('['); + for (int i = 0; i < mPermissions.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(mPermissions[i].toString()); + } + sb.append(']'); + return sb.toString(); + } + + @NonNull String[] toStringArray() { + final String[] names = new String[mPermissions.length]; + for (int i = 0; i < mPermissions.length; i++) { + names[i] = mPermissions[i].mName; + } + return names; + } + } + + /** + * This represents a permission that's going to be required for a specific service type. + * + * @hide + */ + public abstract static class ForegroundServiceTypePermission { + /** + * The name of this permission. + */ + final @NonNull String mName; + + /** + * Constructor. + */ + public ForegroundServiceTypePermission(@NonNull String name) { + mName = name; + } + + /** + * Check if the given uid/pid/package has the access to the permission. + */ + @PackageManager.PermissionResult + public abstract int checkPermission(@NonNull Context context, int callerUid, int callerPid, + @NonNull String packageName, boolean allowWhileInUse); + + @Override + public String toString() { + return mName; + } + } + + /** + * This represents a regular Android permission to be required for a specific service type. + */ + static class RegularPermission extends ForegroundServiceTypePermission { + RegularPermission(@NonNull String name) { + super(name); + } + + @Override + @SuppressLint("AndroidFrameworkRequiresPermission") + @PackageManager.PermissionResult + public int checkPermission(Context context, int callerUid, int callerPid, + String packageName, boolean allowWhileInUse) { + // Simple case, check if it's already granted. + if (context.checkPermission(mName, callerPid, callerUid) == PERMISSION_GRANTED) { + return PERMISSION_GRANTED; + } + if (allowWhileInUse) { + // Check its appops + final int opCode = AppOpsManager.permissionToOpCode(mName); + final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); + if (opCode != AppOpsManager.OP_NONE) { + final int currentMode = appOpsManager.unsafeCheckOpRawNoThrow(opCode, callerUid, + packageName); + if (currentMode == MODE_FOREGROUND) { + // It's in foreground only mode and we're allowing while-in-use. + return PERMISSION_GRANTED; + } + } + } + return PERMISSION_DENIED; + } + } + + /** + * This represents an app op permission to be required for a specific service type. + */ + static class AppOpPermission extends ForegroundServiceTypePermission { + final int mOpCode; + + AppOpPermission(int opCode) { + super(AppOpsManager.opToPublicName(opCode)); + mOpCode = opCode; + } + + @Override + @PackageManager.PermissionResult + public int checkPermission(Context context, int callerUid, int callerPid, + String packageName, boolean allowWhileInUse) { + final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); + final int mode = appOpsManager.unsafeCheckOpRawNoThrow(mOpCode, callerUid, packageName); + return (mode == MODE_ALLOWED || (allowWhileInUse && mode == MODE_FOREGROUND)) + ? PERMISSION_GRANTED : PERMISSION_DENIED; + } + } + + /** + * This represents a special Android permission to be required for accessing usb devices. + */ + static class UsbDevicePermission extends ForegroundServiceTypePermission { + UsbDevicePermission() { + super("USB Device"); + } + + @Override + @SuppressLint("AndroidFrameworkRequiresPermission") + @PackageManager.PermissionResult + public int checkPermission(Context context, int callerUid, int callerPid, + String packageName, boolean allowWhileInUse) { + final UsbManager usbManager = context.getSystemService(UsbManager.class); + final HashMap<String, UsbDevice> devices = usbManager.getDeviceList(); + if (!ArrayUtils.isEmpty(devices)) { + for (UsbDevice device : devices.values()) { + if (usbManager.hasPermission(device, packageName, callerPid, callerUid)) { + return PERMISSION_GRANTED; + } + } + } + return PERMISSION_DENIED; + } + } + + /** + * This represents a special Android permission to be required for accessing usb accessories. + */ + static class UsbAccessoryPermission extends ForegroundServiceTypePermission { + UsbAccessoryPermission() { + super("USB Accessory"); + } + + @Override + @SuppressLint("AndroidFrameworkRequiresPermission") + @PackageManager.PermissionResult + public int checkPermission(Context context, int callerUid, int callerPid, + String packageName, boolean allowWhileInUse) { + final UsbManager usbManager = context.getSystemService(UsbManager.class); + final UsbAccessory[] accessories = usbManager.getAccessoryList(); + if (!ArrayUtils.isEmpty(accessories)) { + for (UsbAccessory accessory: accessories) { + if (usbManager.hasPermission(accessory, callerPid, callerUid)) { + return PERMISSION_GRANTED; + } + } + } + return PERMISSION_DENIED; + } + } + + /** + * The default policy for the foreground service types. + * + * @hide + */ + public static class DefaultForegroundServiceTypePolicy extends ForegroundServiceTypePolicy { + private final SparseArray<ForegroundServiceTypePolicyInfo> mForegroundServiceTypePolicies = + new SparseArray<>(); + + /** + * Constructor + */ + public DefaultForegroundServiceTypePolicy() { + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_NONE, + FGS_TYPE_POLICY_NONE); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_DATA_SYNC, + FGS_TYPE_POLICY_DATA_SYNC); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, + FGS_TYPE_POLICY_MEDIA_PLAYBACK); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_PHONE_CALL, + FGS_TYPE_POLICY_PHONE_CALL); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_LOCATION, + FGS_TYPE_POLICY_LOCATION); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE, + FGS_TYPE_POLICY_CONNECTED_DEVICE); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION, + FGS_TYPE_POLICY_MEDIA_PROJECTION); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_CAMERA, + FGS_TYPE_POLICY_CAMERA); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_MICROPHONE, + FGS_TYPE_POLICY_MICROPHONE); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_HEALTH, + FGS_TYPE_POLICY_HEALTH); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING, + FGS_TYPE_POLICY_REMOTE_MESSAGING); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED, + FGS_TYPE_POLICY_SYSTEM_EXEMPTED); + mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SPECIAL_USE, + FGS_TYPE_POLICY_SPECIAL_USE); + } + + @Override + public ForegroundServiceTypePolicyInfo getForegroundServiceTypePolicyInfo( + @ForegroundServiceType int type, @ForegroundServiceType int defaultToType) { + ForegroundServiceTypePolicyInfo info = mForegroundServiceTypePolicies.get(type); + if (info == null) { + // Unknown type, fallback to the defaultToType + info = mForegroundServiceTypePolicies.get(defaultToType); + if (info == null) { + // It shouldn't happen. + throw new IllegalArgumentException("Invalid default fgs type " + defaultToType); + } + } + return info; + } + + @Override + @SuppressLint("AndroidFrameworkRequiresPermission") + @ForegroundServicePolicyCheckCode + public int checkForegroundServiceTypePolicy(Context context, String packageName, + int callerUid, int callerPid, boolean allowWhileInUse, + @NonNull ForegroundServiceTypePolicyInfo policy) { + // Has this FGS type been disabled and not allowed to use anymore? + if (policy.isTypeDisabled(callerUid)) { + return FGS_TYPE_POLICY_CHECK_DISABLED; + } + int permissionResult = PERMISSION_DENIED; + // Do we have the permission to start FGS with this type. + if (policy.mAllOfPermissions != null) { + permissionResult = policy.mAllOfPermissions.checkPermissions(context, + callerUid, callerPid, packageName, allowWhileInUse); + } + // If it has the "all of" permissions granted, check the "any of" ones. + if (permissionResult == PERMISSION_GRANTED) { + boolean checkCustomPermission = true; + // Check the "any of" permissions. + if (policy.mAnyOfPermissions != null) { + permissionResult = policy.mAnyOfPermissions.checkPermissions(context, + callerUid, callerPid, packageName, allowWhileInUse); + if (permissionResult == PERMISSION_GRANTED) { + // We have one of them granted, no need to check custom permissions. + checkCustomPermission = false; + } + } + // If we have a customized permission checker, also call it now. + if (checkCustomPermission && policy.mCustomPermission != null) { + permissionResult = policy.mCustomPermission.checkPermission(context, + callerUid, callerPid, packageName, allowWhileInUse); + } + } + if (permissionResult != PERMISSION_GRANTED) { + return (CompatChanges.isChangeEnabled( + FGS_TYPE_PERMISSION_CHANGE_ID, callerUid)) + ? FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_ENFORCED + : FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_PERMISSIVE; + } + // Has this FGS type been deprecated? + if (policy.isTypeDeprecated(callerUid)) { + return FGS_TYPE_POLICY_CHECK_DEPRECATED; + } + return FGS_TYPE_POLICY_CHECK_OK; + } + } +} diff --git a/core/java/android/app/SearchableInfo.java b/core/java/android/app/SearchableInfo.java index 5388282a1b46..bd5d1057f5bf 100644 --- a/core/java/android/app/SearchableInfo.java +++ b/core/java/android/app/SearchableInfo.java @@ -396,6 +396,17 @@ public final class SearchableInfo implements Parcelable { private final String mSuggestActionMsg; private final String mSuggestActionMsgColumn; + public static final Parcelable.Creator<ActionKeyInfo> CREATOR = + new Parcelable.Creator<ActionKeyInfo>() { + public ActionKeyInfo createFromParcel(Parcel in) { + return new ActionKeyInfo(in); + } + + public ActionKeyInfo[] newArray(int size) { + return new ActionKeyInfo[size]; + } + }; + /** * Create one object using attributeset as input data. * @param activityContext runtime context of the activity that the action key information diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 7635138f6cdd..01e4b150fd7c 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -21,6 +21,7 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentCallbacks2; import android.content.ComponentName; @@ -726,10 +727,32 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac * for more details. * </div> * + * <div class="caution"> + * <p><strong>Note:</strong> + * Beginning with SDK Version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} + * or higher are not allowed to start foreground services without specifying a valid + * foreground service type in the manifest attribute + * {@link android.R.attr#foregroundServiceType}. + * See + * <a href="{@docRoot}/about/versions/14/behavior-changes-14"> + * Behavior changes: Apps targeting Android 14 + * </a> + * for more details. + * </div> + * * @throws ForegroundServiceStartNotAllowedException * If the app targeting API is * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from * becoming foreground service due to background restriction. + * @throws ForegroundServiceTypeNotAllowedException + * If the app targeting API is + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later, and the manifest attribute + * {@link android.R.attr#foregroundServiceType} is not set. + * @throws SecurityException If the app targeting API is + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later and doesn't have the + * permission to start the foreground service with the specified type in the manifest attribute + * {@link android.R.attr#foregroundServiceType}. * * @param id The identifier for this notification as per * {@link NotificationManager#notify(int, Notification) @@ -748,51 +771,77 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac } } - /** - * An overloaded version of {@link #startForeground(int, Notification)} with additional - * foregroundServiceType parameter. - * - * <p>Apps built with SDK version {@link android.os.Build.VERSION_CODES#Q} or later can specify - * the foreground service types using attribute {@link android.R.attr#foregroundServiceType} in - * service element of manifest file. The value of attribute - * {@link android.R.attr#foregroundServiceType} can be multiple flags ORed together.</p> - * - * <p>The foregroundServiceType parameter must be a subset flags of what is specified in manifest - * attribute {@link android.R.attr#foregroundServiceType}, if not, an IllegalArgumentException is - * thrown. Specify foregroundServiceType parameter as - * {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST} to use all flags that - * is specified in manifest attribute foregroundServiceType.</p> - * - * <div class="caution"> - * <p><strong>Note:</strong> - * Beginning with SDK Version {@link android.os.Build.VERSION_CODES#S}, - * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} - * or higher are not allowed to start foreground services from the background. - * See - * <a href="{@docRoot}/about/versions/12/behavior-changes-12"> - * Behavior changes: Apps targeting Android 12 - * </a> - * for more details. - * </div> - * - * @param id The identifier for this notification as per - * {@link NotificationManager#notify(int, Notification) - * NotificationManager.notify(int, Notification)}; must not be 0. - * @param notification The Notification to be displayed. - * @param foregroundServiceType must be a subset flags of manifest attribute - * {@link android.R.attr#foregroundServiceType} flags. - * - * @throws IllegalArgumentException if param foregroundServiceType is not subset of manifest - * attribute {@link android.R.attr#foregroundServiceType}. - * @throws ForegroundServiceStartNotAllowedException - * If the app targeting API is - * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from - * becoming foreground service due to background restriction. - * - * @see android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST - */ + /** + * An overloaded version of {@link #startForeground(int, Notification)} with additional + * foregroundServiceType parameter. + * + * <p>Apps built with SDK version {@link android.os.Build.VERSION_CODES#Q} or later can specify + * the foreground service types using attribute {@link android.R.attr#foregroundServiceType} in + * service element of manifest file. The value of attribute + * {@link android.R.attr#foregroundServiceType} can be multiple flags ORed together.</p> + * + * <p>The foregroundServiceType parameter must be a subset flags of what is specified in + * manifest attribute {@link android.R.attr#foregroundServiceType}, if not, an + * IllegalArgumentException is thrown. Specify foregroundServiceType parameter as + * {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST} to use all flags that + * is specified in manifest attribute foregroundServiceType.</p> + * + * <div class="caution"> + * <p><strong>Note:</strong> + * Beginning with SDK Version {@link android.os.Build.VERSION_CODES#S}, + * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S} + * or higher are not allowed to start foreground services from the background. + * See + * <a href="{@docRoot}/about/versions/12/behavior-changes-12"> + * Behavior changes: Apps targeting Android 12 + * </a> + * for more details. + * </div> + * + * <div class="caution"> + * <p><strong>Note:</strong> + * Beginning with SDK Version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, + * apps targeting SDK Version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} + * or higher are not allowed to start foreground services without specifying a valid + * foreground service type in the manifest attribute + * {@link android.R.attr#foregroundServiceType}, and the parameter {@code foregroundServiceType} + * here must not be the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}. + * See + * <a href="{@docRoot}/about/versions/14/behavior-changes-14"> + * Behavior changes: Apps targeting Android 14 + * </a> + * for more details. + * </div> + * + * @param id The identifier for this notification as per + * {@link NotificationManager#notify(int, Notification) + * NotificationManager.notify(int, Notification)}; must not be 0. + * @param notification The Notification to be displayed. + * @param foregroundServiceType must be a subset flags of manifest attribute + * {@link android.R.attr#foregroundServiceType} flags; must not be + * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}. + * + * @throws IllegalArgumentException if param foregroundServiceType is not subset of manifest + * attribute {@link android.R.attr#foregroundServiceType}. + * @throws ForegroundServiceStartNotAllowedException + * If the app targeting API is + * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from + * becoming foreground service due to background restriction. + * @throws ForegroundServiceTypeNotAllowedException + * If the app targeting API is + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later, and the manifest attribute + * {@link android.R.attr#foregroundServiceType} is not set, or the param + * {@code foregroundServiceType} is {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}. + * @throws SecurityException If the app targeting API is + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later and doesn't have the + * permission to start the foreground service with the specified type in + * {@code foregroundServiceType}. + * {@link android.R.attr#foregroundServiceType}. + * + * @see android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST + */ public final void startForeground(int id, @NonNull Notification notification, - @ForegroundServiceType int foregroundServiceType) { + @RequiresPermission @ForegroundServiceType int foregroundServiceType) { try { mActivityManager.setServiceForeground( new ComponentName(this, mClassName), mToken, id, diff --git a/core/java/android/content/ActivityNotFoundException.java b/core/java/android/content/ActivityNotFoundException.java index 16149bbc7012..5b50189015af 100644 --- a/core/java/android/content/ActivityNotFoundException.java +++ b/core/java/android/content/ActivityNotFoundException.java @@ -31,5 +31,4 @@ public class ActivityNotFoundException extends RuntimeException { super(name); } -}; - +} diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java index f888813135be..1b5f64c456a1 100644 --- a/core/java/android/content/integrity/AtomicFormula.java +++ b/core/java/android/content/integrity/AtomicFormula.java @@ -261,8 +261,8 @@ public abstract class AtomicFormula extends IntegrityFormula { } LongAtomicFormula that = (LongAtomicFormula) o; return getKey() == that.getKey() - && mValue == that.mValue - && mOperator == that.mOperator; + && Objects.equals(mValue, that.mValue) + && Objects.equals(mOperator, that.mOperator); } @Override @@ -628,7 +628,7 @@ public abstract class AtomicFormula extends IntegrityFormula { return false; } BooleanAtomicFormula that = (BooleanAtomicFormula) o; - return getKey() == that.getKey() && mValue == that.mValue; + return getKey() == that.getKey() && Objects.equals(mValue, that.mValue); } @Override diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index dc6a8c95f290..6c1d84be6c9f 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -165,6 +165,21 @@ public abstract class PackageManager { "android.internal.PROPERTY_NO_APP_DATA_STORAGE"; /** + * <service> level {@link android.content.pm.PackageManager.Property} tag specifying + * the actual use case of the service if it's foreground service with the type + * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SPECIAL_USE}. + * + * <p> + * For example: + * <service> + * <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" + * android:value="foo"/> + * </service> + */ + public static final String PROPERTY_SPECIAL_USE_FGS_SUBTYPE = + "android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"; + + /** * A property value set within the manifest. * <p> * The value of a property will only have a single type, as defined by @@ -189,12 +204,12 @@ public abstract class PackageManager { @VisibleForTesting public Property(@NonNull String name, int type, @NonNull String packageName, @Nullable String className) { - assert name != null; - assert type >= TYPE_BOOLEAN && type <= TYPE_STRING; - assert packageName != null; - this.mName = name; + if (type < TYPE_BOOLEAN || type > TYPE_STRING) { + throw new IllegalArgumentException("Invalid type"); + } + this.mName = Objects.requireNonNull(name); this.mType = type; - this.mPackageName = packageName; + this.mPackageName = Objects.requireNonNull(packageName); this.mClassName = className; } /** @hide */ @@ -442,9 +457,8 @@ public abstract class PackageManager { */ public ComponentEnabledSetting(@NonNull ComponentName componentName, @EnabledState int newState, @EnabledFlags int flags) { - Objects.nonNull(componentName); mPackageName = null; - mComponentName = componentName; + mComponentName = Objects.requireNonNull(componentName); mEnabledState = newState; mEnabledFlags = flags; } @@ -460,8 +474,7 @@ public abstract class PackageManager { */ public ComponentEnabledSetting(@NonNull String packageName, @EnabledState int newState, @EnabledFlags int flags) { - Objects.nonNull(packageName); - mPackageName = packageName; + mPackageName = Objects.requireNonNull(packageName); mComponentName = null; mEnabledState = newState; mEnabledFlags = flags; diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index 88d700432e8a..ab20b6f7f9cc 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -16,7 +16,9 @@ package android.content.pm; +import android.Manifest; import android.annotation.IntDef; +import android.annotation.RequiresPermission; import android.os.Parcel; import android.os.Parcelable; import android.util.Printer; @@ -100,7 +102,15 @@ public class ServiceInfo extends ComponentInfo /** * The default foreground service type if not been set in manifest file. + * + * <p>Apps targeting API level {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and + * later should NOT use this type, + * calling {@link android.app.Service#startForeground(int, android.app.Notification, int)} with + * this type will get a {@link android.app.ForegroundServiceTypeNotAllowedException}.</p> + * + * @deprecated Do not use. */ + @Deprecated public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; /** @@ -108,14 +118,36 @@ public class ServiceInfo extends ComponentInfo * the {@link android.R.attr#foregroundServiceType} attribute. * Data(photo, file, account) upload/download, backup/restore, import/export, fetch, * transfer over network between device and cloud. + * + * <p>Apps targeting API level {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and + * later should NOT use this type: + * calling {@link android.app.Service#startForeground(int, android.app.Notification, int)} with + * this type on devices running {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} is still + * allowed, but calling it with this type on devices running future platform releases may get a + * {@link android.app.ForegroundServiceTypeNotAllowedException}.</p> + * + * @deprecated Use {@link android.app.job.JobInfo.Builder} data transfer APIs instead. */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, + conditional = true + ) + @Deprecated public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1 << 0; /** * Constant corresponding to <code>mediaPlayback</code> in * the {@link android.R.attr#foregroundServiceType} attribute. * Music, video, news or other media playback. + * + * <p>Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_MEDIA_PLAYBACK}. */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 1 << 1; /** @@ -123,28 +155,94 @@ public class ServiceInfo extends ComponentInfo * the {@link android.R.attr#foregroundServiceType} attribute. * Ongoing operations related to phone calls, video conferencing, * or similar interactive communication. + * + * <p>Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_PHONE_CALL} and + * {@link android.Manifest.permission#MANAGE_OWN_CALLS}. */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL, + }, + anyOf = { + Manifest.permission.MANAGE_OWN_CALLS, + }, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 1 << 2; /** * Constant corresponding to <code>location</code> in * the {@link android.R.attr#foregroundServiceType} attribute. * GPS, map, navigation location update. + * + * <p>Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_LOCATION} and one of the + * following permissions: + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}, + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_LOCATION, + }, + anyOf = { + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + }, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 1 << 3; /** * Constant corresponding to <code>connectedDevice</code> in * the {@link android.R.attr#foregroundServiceType} attribute. * Auto, bluetooth, TV or other devices connection, monitoring and interaction. + * + * <p>Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_CONNECTED_DEVICE} and one of the + * following permissions: + * {@link android.Manifest.permission#BLUETOOTH_CONNECT}, + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}, + * {@link android.Manifest.permission#CHANGE_WIFI_STATE}, + * {@link android.Manifest.permission#CHANGE_WIFI_MULTICAST_STATE}, + * {@link android.Manifest.permission#NFC}, + * {@link android.Manifest.permission#TRANSMIT_IR}, + * or has been granted the access to one of the attached USB devices/accessories. */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE, + }, + anyOf = { + Manifest.permission.BLUETOOTH_CONNECT, + Manifest.permission.CHANGE_NETWORK_STATE, + Manifest.permission.CHANGE_WIFI_STATE, + Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, + Manifest.permission.NFC, + Manifest.permission.TRANSMIT_IR, + }, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 1 << 4; /** * Constant corresponding to {@code mediaProjection} in * the {@link android.R.attr#foregroundServiceType} attribute. * Managing a media projection session, e.g for screen recording or taking screenshots. + * + * <p>Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_MEDIA_PROJECTION}, and the user must + * have allowed the screen capture request from this app. */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION = 1 << 5; /** @@ -155,7 +253,21 @@ public class ServiceInfo extends ComponentInfo * above, a foreground service will not be able to access the camera if this type is not * specified in the manifest and in * {@link android.app.Service#startForeground(int, android.app.Notification, int)}. + * + * <p>Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_CAMERA} and + * {@link android.Manifest.permission#CAMERA}. */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_CAMERA, + }, + anyOf = { + Manifest.permission.CAMERA, + }, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 1 << 6; /** @@ -166,17 +278,148 @@ public class ServiceInfo extends ComponentInfo * above, a foreground service will not be able to access the microphone if this type is not * specified in the manifest and in * {@link android.app.Service#startForeground(int, android.app.Notification, int)}. + * + * <p>Starting foreground service with this type from apps targeting API level + * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission + * {@link android.Manifest.permission#FOREGROUND_SERVICE_MICROPHONE} and one of the following + * permissions: + * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT}, + * {@link android.Manifest.permission#RECORD_AUDIO}. */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_MICROPHONE, + }, + anyOf = { + Manifest.permission.CAPTURE_AUDIO_OUTPUT, + Manifest.permission.RECORD_AUDIO, + }, + conditional = true + ) public static final int FOREGROUND_SERVICE_TYPE_MICROPHONE = 1 << 7; /** - * The number of foreground service types, this doesn't include - * the {@link #FOREGROUND_SERVICE_TYPE_MANIFEST} and {@link #FOREGROUND_SERVICE_TYPE_NONE} - * as they're not real service types. + * Constant corresponding to {@code health} in + * the {@link android.R.attr#foregroundServiceType} attribute. + * Health, wellness and fitness. + * + * <p>The caller app is required to have the permissions + * {@link android.Manifest.permission#FOREGROUND_SERVICE_HEALTH} and one of the following + * permissions: + * {@link android.Manifest.permission#ACTIVITY_RECOGNITION}, + * {@link android.Manifest.permission#BODY_SENSORS}, + * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS}. + */ + @RequiresPermission( + allOf = { + Manifest.permission.FOREGROUND_SERVICE_HEALTH, + }, + anyOf = { + Manifest.permission.ACTIVITY_RECOGNITION, + Manifest.permission.BODY_SENSORS, + Manifest.permission.HIGH_SAMPLING_RATE_SENSORS, + }, + conditional = true + ) + public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 1 << 8; + + /** + * Constant corresponding to {@code remoteMessaging} in + * the {@link android.R.attr#foregroundServiceType} attribute. + * Messaging use cases which host local server to relay messages across devices. + */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING, + conditional = true + ) + public static final int FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING = 1 << 9; + + /** + * Constant corresponding to {@code systemExempted} in + * the {@link android.R.attr#foregroundServiceType} attribute. + * The system exmpted foreground service use cases. + * + * <p class="note">Note, apps are allowed to use this type only in the following cases: + * <ul> + * <li>App has a UID < {@link android.os.Process#FIRST_APPLICATION_UID}</li> + * <li>App is on Doze allowlist</li> + * <li>Device is running in <a href="https://android.googlesource.com/platform/frameworks/base/+/master/packages/SystemUI/docs/demo_mode.md">Demo Mode</a></li> + * <li><a href="https://source.android.com/devices/tech/admin/provision">Device owner app</a><li> + * <li><a href="https://source.android.com/devices/tech/admin/managed-profiles">Profile owner apps</a><li> + * <li>Persistent apps</li> + * <li><a href="https://source.android.com/docs/core/connect/carrier">Carrier privileged apps</a></li> + * <li>Apps that have the {@code android.app.role.RoleManager#ROLE_EMERGENCY} role</li> + * <li>Headless system apps</li> + * <li><a href="{@docRoot}guide/topics/admin/device-admin">Device admin apps</a></li> + * <li>Active VPN apps</li> + * <li>Apps holding {@link Manifest.permission#SCHEDULE_EXACT_ALARM} or + * {@link Manifest.permission#USE_EXACT_ALARM} permission.</li> + * </ul> + * </p> + */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED, + conditional = true + ) + public static final int FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED = 1 << 10; + + /** + * Constant corresponding to {@code specialUse} in + * the {@link android.R.attr#foregroundServiceType} attribute. + * Use cases that can't be categorized into any other foreground service types, but also + * can't use {@link android.app.job.JobInfo.Builder} APIs. + * + * <p>The use of this foreground service type may be restricted. Additionally, apps must declare + * a service-level {@link PackageManager#PROPERTY_SPECIAL_USE_FGS_SUBTYPE <property>} in + * {@code AndroidManifest.xml} as a hint of what the exact use case here is. + * Here is an example: + * <pre> + * <uses-permission + * android:name="android.permissions.FOREGROUND_SERVICE_SPECIAL_USE" + * /> + * <service + * android:name=".MySpecialForegroundService" + * android:foregroundServiceType="specialUse"> + * <property + * android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" + * android:value="foo" + * /> + * </service> + * </pre> + * + * In a future release of Android, if the above foreground service type {@code foo} is supported + * by the platform, to offer the backward compatibility, the app could specify + * the {@code android:maxSdkVersion} attribute in the <uses-permission> section, + * and also add the foreground service type {@code foo} into + * the {@code android:foregroundServiceType}, therefore the same app could be installed + * in both platforms. + * <pre> + * <uses-permission + * android:name="android.permissions.FOREGROUND_SERVICE_SPECIAL_USE" + * android:maxSdkVersion="last_sdk_version_without_type_foo" + * /> + * <service + * android:name=".MySpecialForegroundService" + * android:foregroundServiceType="specialUse|foo"> + * <property + * android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"" + * android:value="foo" + * /> + * </service> + * </pre> + */ + @RequiresPermission( + value = Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE, + conditional = true + ) + public static final int FOREGROUND_SERVICE_TYPE_SPECIAL_USE = 1 << 30; + + /** + * The max index being used in the definition of foreground service types. * * @hide */ - public static final int NUM_OF_FOREGROUND_SERVICE_TYPES = 8; + public static final int FOREGROUND_SERVICE_TYPES_MAX_INDEX = 30; /** * A special value indicates to use all types set in manifest file. @@ -199,7 +442,11 @@ public class ServiceInfo extends ComponentInfo FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE, FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION, FOREGROUND_SERVICE_TYPE_CAMERA, - FOREGROUND_SERVICE_TYPE_MICROPHONE + FOREGROUND_SERVICE_TYPE_MICROPHONE, + FOREGROUND_SERVICE_TYPE_HEALTH, + FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING, + FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED, + FOREGROUND_SERVICE_TYPE_SPECIAL_USE }) @Retention(RetentionPolicy.SOURCE) public @interface ForegroundServiceType {} @@ -275,6 +522,14 @@ public class ServiceInfo extends ComponentInfo return "camera"; case FOREGROUND_SERVICE_TYPE_MICROPHONE: return "microphone"; + case FOREGROUND_SERVICE_TYPE_HEALTH: + return "health"; + case FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING: + return "remoteMessaging"; + case FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED: + return "systemExempted"; + case FOREGROUND_SERVICE_TYPE_SPECIAL_USE: + return "specialUse"; default: return "unknown"; } diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 1f83d7532f04..295df5cc42d0 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -50,6 +50,7 @@ import android.view.contentcapture.ContentCaptureContext; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; +import java.lang.IllegalArgumentException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -1360,7 +1361,9 @@ public final class ShortcutInfo implements Parcelable { @NonNull public Builder setIntents(@NonNull Intent[] intents) { Objects.requireNonNull(intents, "intents cannot be null"); - Objects.requireNonNull(intents.length, "intents cannot be empty"); + if (intents.length == 0) { + throw new IllegalArgumentException("intents cannot be empty"); + } for (Intent intent : intents) { Objects.requireNonNull(intent, "intents cannot contain null"); Objects.requireNonNull(intent.getAction(), "intent's action must be set"); @@ -1398,7 +1401,9 @@ public final class ShortcutInfo implements Parcelable { @NonNull public Builder setPersons(@NonNull Person[] persons) { Objects.requireNonNull(persons, "persons cannot be null"); - Objects.requireNonNull(persons.length, "persons cannot be empty"); + if (persons.length == 0) { + throw new IllegalArgumentException("persons cannot be empty"); + } for (Person person : persons) { Objects.requireNonNull(person, "persons cannot contain null"); } diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 9baa6ba2fb49..2be0323a1e8b 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -159,6 +159,18 @@ public class UserInfo implements Parcelable { public static final int FLAG_EPHEMERAL_ON_CREATE = 0x00002000; /** + * Indicates that this user is the designated main user on the device. This user may have access + * to certain features which are limited to at most one user. + * + * <p>Currently, this will be the first user to go through setup on the device, but in future + * releases this status may be transferable or may even not be given to any users. + * + * <p>This is not necessarily the system user. For example, it will not be the system user on + * devices for which {@link UserManager#isHeadlessSystemUserMode()} returns true. + */ + public static final int FLAG_MAIN = 0x00004000; + + /** * @hide */ @IntDef(flag = true, prefix = "FLAG_", value = { @@ -175,7 +187,8 @@ public class UserInfo implements Parcelable { FLAG_FULL, FLAG_SYSTEM, FLAG_PROFILE, - FLAG_EPHEMERAL_ON_CREATE + FLAG_EPHEMERAL_ON_CREATE, + FLAG_MAIN }) @Retention(RetentionPolicy.SOURCE) public @interface UserInfoFlag { @@ -369,6 +382,13 @@ public class UserInfo implements Parcelable { } /** + * @see #FLAG_MAIN + */ + public boolean isMain() { + return (flags & FLAG_MAIN) == FLAG_MAIN; + } + + /** * Returns true if the user is a split system user. * <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled, * the method always returns false. diff --git a/core/java/android/hardware/CameraInfo.java b/core/java/android/hardware/CameraInfo.java index 072be50ad2fb..41ef6aa54ae3 100644 --- a/core/java/android/hardware/CameraInfo.java +++ b/core/java/android/hardware/CameraInfo.java @@ -60,4 +60,4 @@ public class CameraInfo implements Parcelable { return new CameraInfo[size]; } }; -}; +} diff --git a/core/java/android/hardware/CameraStatus.java b/core/java/android/hardware/CameraStatus.java index 874af297683e..fa35efbcee91 100644 --- a/core/java/android/hardware/CameraStatus.java +++ b/core/java/android/hardware/CameraStatus.java @@ -68,4 +68,4 @@ public class CameraStatus implements Parcelable { return new CameraStatus[size]; } }; -}; +} diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java index d41570682fe1..267ef3637ce7 100644 --- a/core/java/android/hardware/biometrics/CryptoObject.java +++ b/core/java/android/hardware/biometrics/CryptoObject.java @@ -118,4 +118,4 @@ public class CryptoObject { } return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto); } -}; +} diff --git a/core/java/android/hardware/camera2/impl/FrameNumberTracker.java b/core/java/android/hardware/camera2/impl/FrameNumberTracker.java index 7b6a457411f3..8304796f636a 100644 --- a/core/java/android/hardware/camera2/impl/FrameNumberTracker.java +++ b/core/java/android/hardware/camera2/impl/FrameNumberTracker.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.TreeMap; /** @@ -63,11 +64,11 @@ public class FrameNumberTracker { } private void update() { - Iterator iter = mFutureErrorMap.entrySet().iterator(); + Iterator<Map.Entry<Long, Integer>> iter = mFutureErrorMap.entrySet().iterator(); while (iter.hasNext()) { - TreeMap.Entry pair = (TreeMap.Entry)iter.next(); - Long errorFrameNumber = (Long)pair.getKey(); - int requestType = (int) pair.getValue(); + Map.Entry<Long, Integer> pair = iter.next(); + long errorFrameNumber = pair.getKey(); + int requestType = pair.getValue(); Boolean removeError = false; if (errorFrameNumber == mCompletedFrameNumber[requestType] + 1) { removeError = true; diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java index 621a418f43c9..92a2fb6f16b1 100644 --- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java +++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java @@ -103,6 +103,7 @@ public class MarshalQueryableEnum<T extends Enum<T>> implements MarshalQueryable return new MarshalerEnum(managedType, nativeType); } + @SuppressWarnings("ReturnValueIgnored") @Override public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) { if (nativeType == TYPE_INT32 || nativeType == TYPE_BYTE) { diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index a0d8f8db6853..f4b87b9f5ae9 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -1344,7 +1344,8 @@ public final class OutputConfiguration implements Parcelable { return false; } for (int j = 0; j < mSensorPixelModesUsed.size(); j++) { - if (mSensorPixelModesUsed.get(j) != other.mSensorPixelModesUsed.get(j)) { + if (!Objects.equals( + mSensorPixelModesUsed.get(j), other.mSensorPixelModesUsed.get(j))) { return false; } } diff --git a/core/java/android/hardware/fingerprint/Fingerprint.java b/core/java/android/hardware/fingerprint/Fingerprint.java index 9ce834ca5981..c01c94c43997 100644 --- a/core/java/android/hardware/fingerprint/Fingerprint.java +++ b/core/java/android/hardware/fingerprint/Fingerprint.java @@ -69,4 +69,4 @@ public final class Fingerprint extends BiometricAuthenticator.Identifier { return new Fingerprint[size]; } }; -};
\ No newline at end of file +}
\ No newline at end of file diff --git a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java index f8e25584c419..d4b76c888eac 100644 --- a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java +++ b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java @@ -53,8 +53,8 @@ import java.lang.annotation.RetentionPolicy; import java.net.ProtocolException; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; /** @@ -89,12 +89,10 @@ public class NetworkStatsDataMigrationUtils { @Retention(RetentionPolicy.SOURCE) public @interface Prefix {} - private static final HashMap<String, String> sPrefixLegacyFileNameMap = - new HashMap<String, String>() {{ - put(PREFIX_XT, "netstats_xt.bin"); - put(PREFIX_UID, "netstats_uid.bin"); - put(PREFIX_UID_TAG, "netstats_uid.bin"); - }}; + private static final Map<String, String> sPrefixLegacyFileNameMap = Map.of( + PREFIX_XT, "netstats_xt.bin", + PREFIX_UID, "netstats_uid.bin", + PREFIX_UID_TAG, "netstats_uid.bin"); // These version constants are copied from NetworkStatsCollection/History, which is okay for // OEMs to modify to adapt their own logic. diff --git a/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java index 4bc5b49aa207..0427742f9c0a 100644 --- a/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java +++ b/core/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtils.java @@ -53,7 +53,7 @@ public final class TunnelConnectionParamsUtils { if (in.keySet().size() != EXPECTED_BUNDLE_KEY_CNT) { throw new IllegalArgumentException( String.format( - "Expect PersistableBundle to have %d element but found: %d", + "Expect PersistableBundle to have %d element but found: %s", EXPECTED_BUNDLE_KEY_CNT, in.keySet())); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index fbfe548416fe..1f21bfe6cd72 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -2341,12 +2341,18 @@ public class UserManager { } /** - * Used to check if the context user is the primary user. The primary user - * is the first human user on a device. This is not supported in headless system user mode. + * Used to check if the context user is the primary user. The primary user is the first human + * user on a device. This is not supported in headless system user mode. * * @return whether the context user is the primary user. + * + * @deprecated This method always returns true for the system user, who may not be a full user + * if {@link #isHeadlessSystemUserMode} is true. Use {@link #isSystemUser}, {@link #isAdminUser} + * or {@link #isMainUser} instead. + * * @hide */ + @Deprecated @SystemApi @RequiresPermission(anyOf = { Manifest.permission.MANAGE_USERS, @@ -2371,6 +2377,29 @@ public class UserManager { } /** + * Returns true if the context user is the designated "main user" of the device. This user may + * have access to certain features which are limited to at most one user. + * + * <p>Currently, the first human user on the device will be the main user; in the future, the + * concept may be transferable, so a different user (or even no user at all) may be designated + * the main user instead. + * + * <p>Note that this will be the not be the system user on devices for which + * {@link #isHeadlessSystemUserMode()} returns true. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS, + Manifest.permission.QUERY_USERS}) + @UserHandleAware + public boolean isMainUser() { + final UserInfo user = getUserInfo(mUserId); + return user != null && user.isMain(); + } + + /** * Used to check if the context user is an admin user. An admin user is allowed to * modify or configure certain settings that aren't available to non-admin users, * create and delete additional users, etc. There can be more than one admin users. diff --git a/core/java/android/security/keymaster/ExportResult.java b/core/java/android/security/keymaster/ExportResult.java index 2c382efab1be..c78fb1a1f6b5 100644 --- a/core/java/android/security/keymaster/ExportResult.java +++ b/core/java/android/security/keymaster/ExportResult.java @@ -61,4 +61,4 @@ public class ExportResult implements Parcelable { out.writeInt(resultCode); out.writeByteArray(exportData); } -}; +} diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java index aa45c20a8e13..6e8198ba0cd1 100644 --- a/core/java/android/service/dreams/DreamOverlayService.java +++ b/core/java/android/service/dreams/DreamOverlayService.java @@ -49,6 +49,17 @@ public abstract class DreamOverlayService extends Service { mShowComplications = shouldShowComplications; onStartDream(layoutParams); } + + @Override + public void wakeUp() { + onWakeUp(() -> { + try { + mDreamOverlayCallback.onWakeUpComplete(); + } catch (RemoteException e) { + Log.e(TAG, "Could not notify dream of wakeUp:" + e); + } + }); + } }; IDreamOverlayCallback mDreamOverlayCallback; @@ -71,6 +82,17 @@ public abstract class DreamOverlayService extends Service { public abstract void onStartDream(@NonNull WindowManager.LayoutParams layoutParams); /** + * This method is overridden by implementations to handle when the dream has been requested + * to wakeup. This allows any overlay animations to run. + * + * @param onCompleteCallback The callback to trigger to notify the dream service that the + * overlay has completed waking up. + * @hide + */ + public void onWakeUp(@NonNull Runnable onCompleteCallback) { + } + + /** * This method is invoked to request the dream exit. */ public final void requestExit() { diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index bb22920b7c65..8b9852a8f1b7 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -312,7 +312,14 @@ public class DreamService extends Service implements Window.Callback { @Override public void onExitRequested() { // Simply finish dream when exit is requested. - finish(); + mHandler.post(() -> finish()); + } + + @Override + public void onWakeUpComplete() { + // Finish the dream once overlay animations are complete. Execute on handler since + // this is coming in on the overlay binder. + mHandler.post(() -> finish()); } }; @@ -975,7 +982,18 @@ public class DreamService extends Service implements Window.Callback { * </p> */ public void onWakeUp() { - finish(); + if (mOverlayConnection != null) { + mOverlayConnection.addConsumer(overlay -> { + try { + overlay.wakeUp(); + } catch (RemoteException e) { + Slog.e(TAG, "Error waking the overlay service", e); + finish(); + } + }); + } else { + finish(); + } } /** {@inheritDoc} */ diff --git a/core/java/android/service/dreams/IDreamOverlay.aidl b/core/java/android/service/dreams/IDreamOverlay.aidl index 05ebbfe98c9f..7aeceb2ce538 100644 --- a/core/java/android/service/dreams/IDreamOverlay.aidl +++ b/core/java/android/service/dreams/IDreamOverlay.aidl @@ -38,4 +38,7 @@ interface IDreamOverlay { */ void startDream(in LayoutParams params, in IDreamOverlayCallback callback, in String dreamComponent, in boolean shouldShowComplications); + + /** Called when the dream is waking, to do any exit animations */ + void wakeUp(); } diff --git a/core/java/android/service/dreams/IDreamOverlayCallback.aidl b/core/java/android/service/dreams/IDreamOverlayCallback.aidl index ec76a334d5b2..4ad63f1317d1 100644 --- a/core/java/android/service/dreams/IDreamOverlayCallback.aidl +++ b/core/java/android/service/dreams/IDreamOverlayCallback.aidl @@ -28,4 +28,7 @@ interface IDreamOverlayCallback { * Invoked to request the dream exit. */ void onExitRequested(); + + /** Invoked when the dream overlay wakeUp animation is complete. */ + void onWakeUpComplete(); }
\ No newline at end of file diff --git a/core/java/android/text/style/AccessibilityURLSpan.java b/core/java/android/text/style/AccessibilityURLSpan.java index bd816234a652..e280bdf8b339 100644 --- a/core/java/android/text/style/AccessibilityURLSpan.java +++ b/core/java/android/text/style/AccessibilityURLSpan.java @@ -26,6 +26,7 @@ import android.view.accessibility.AccessibilityNodeInfo; * It is used to replace URLSpans in {@link AccessibilityNodeInfo#setText(CharSequence)} * @hide */ +@SuppressWarnings("ParcelableCreator") public class AccessibilityURLSpan extends URLSpan implements Parcelable { final AccessibilityClickableSpan mAccessibilityClickableSpan; diff --git a/core/java/android/util/AndroidException.java b/core/java/android/util/AndroidException.java index 1345ddf189e1..d1b9d9f3c53a 100644 --- a/core/java/android/util/AndroidException.java +++ b/core/java/android/util/AndroidException.java @@ -40,5 +40,5 @@ public class AndroidException extends Exception { boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } -}; +} diff --git a/core/java/android/util/AndroidRuntimeException.java b/core/java/android/util/AndroidRuntimeException.java index 2b824bf9cb2a..72c34d8b75ac 100644 --- a/core/java/android/util/AndroidRuntimeException.java +++ b/core/java/android/util/AndroidRuntimeException.java @@ -34,5 +34,4 @@ public class AndroidRuntimeException extends RuntimeException { public AndroidRuntimeException(Exception cause) { super(cause); } -}; - +} diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 7b6a6d29baf8..4afd26879218 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -132,6 +132,12 @@ public class FeatureFlagUtils { */ public static final String SETTINGS_ADB_METRICS_WRITER = "settings_adb_metrics_writer"; + /** + * Flag to enable/disable biometrics enrollment v2 + * @hide + */ + public static final String SETTINGS_BIOMETRICS2_ENROLLMENT = "settings_biometrics2_enrollment"; + private static final Map<String, String> DEFAULT_FLAGS; static { @@ -167,6 +173,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD, "false"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA, "false"); DEFAULT_FLAGS.put(SETTINGS_ADB_METRICS_WRITER, "false"); + DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_ENROLLMENT, "false"); } private static final Set<String> PERSISTENT_FLAGS; diff --git a/core/java/android/util/Range.java b/core/java/android/util/Range.java index 9fd0ab99f01b..41c171a0bbd7 100644 --- a/core/java/android/util/Range.java +++ b/core/java/android/util/Range.java @@ -356,4 +356,4 @@ public final class Range<T extends Comparable<? super T>> { private final T mLower; private final T mUpper; -}; +} diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java index 19de396c4a4a..44318bbc5468 100644 --- a/core/java/android/util/TypedValue.java +++ b/core/java/android/util/TypedValue.java @@ -696,5 +696,5 @@ public class TypedValue { sb.append("}"); return sb.toString(); } -}; +} diff --git a/core/java/android/view/CutoutSpecification.java b/core/java/android/view/CutoutSpecification.java index f8aa934af595..3fc3b6a3ccb3 100644 --- a/core/java/android/view/CutoutSpecification.java +++ b/core/java/android/view/CutoutSpecification.java @@ -394,7 +394,6 @@ public class CutoutSpecification { Log.e(TAG, "According to SVG definition, it shouldn't happen"); return; } - spec.trim(); translateMatrix(); final Path newPath = PathParser.createPathFromPathData(spec); diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java index ea9799584e20..ff282ba0da39 100644 --- a/core/java/android/view/RemoteAnimationDefinition.java +++ b/core/java/android/view/RemoteAnimationDefinition.java @@ -19,6 +19,7 @@ package android.view; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import android.annotation.Nullable; +import android.annotation.NonNull; import android.app.WindowConfiguration.ActivityType; import android.compat.annotation.UnsupportedAppUsage; import android.os.IBinder; @@ -157,7 +158,7 @@ public class RemoteAnimationDefinition implements Parcelable { } } - public static final @android.annotation.NonNull Creator<RemoteAnimationDefinition> CREATOR = + public static final @NonNull Creator<RemoteAnimationDefinition> CREATOR = new Creator<RemoteAnimationDefinition>() { public RemoteAnimationDefinition createFromParcel(Parcel in) { return new RemoteAnimationDefinition(in); @@ -199,18 +200,17 @@ public class RemoteAnimationDefinition implements Parcelable { return 0; } - private static final @android.annotation.NonNull Creator<RemoteAnimationAdapterEntry> CREATOR - = new Creator<RemoteAnimationAdapterEntry>() { - - @Override - public RemoteAnimationAdapterEntry createFromParcel(Parcel in) { - return new RemoteAnimationAdapterEntry(in); - } - - @Override - public RemoteAnimationAdapterEntry[] newArray(int size) { - return new RemoteAnimationAdapterEntry[size]; - } - }; + public static final @NonNull Parcelable.Creator<RemoteAnimationAdapterEntry> CREATOR = + new Parcelable.Creator<RemoteAnimationAdapterEntry>() { + @Override + public RemoteAnimationAdapterEntry createFromParcel(Parcel in) { + return new RemoteAnimationAdapterEntry(in); + } + + @Override + public RemoteAnimationAdapterEntry[] newArray(int size) { + return new RemoteAnimationAdapterEntry[size]; + } + }; } } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index cc85181f52f2..16f6cea2135c 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -3408,6 +3408,11 @@ public interface WindowManager extends ViewManager { * alt="Screenshot of an activity on a display with a cutout on the long edge in portrait, * letterbox is applied."/> * + * <p> + * Note: Android might not allow the content view to overlap the system bars in view level. + * To override this behavior and allow content to be able to extend into the cutout area, + * call {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. + * * @see DisplayCutout * @see WindowInsets#getDisplayCutout() * @see #layoutInDisplayCutoutMode @@ -3443,6 +3448,11 @@ public interface WindowManager extends ViewManager { * In this mode, the window extends under cutouts on the all edges of the display in both * portrait and landscape, regardless of whether the window is hiding the system bars. * + * <p> + * Note: Android might not allow the content view to overlap the system bars in view level. + * To override this behavior and allow content to be able to extend into the cutout area, + * call {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. + * * @see DisplayCutout * @see WindowInsets#getDisplayCutout() * @see #layoutInDisplayCutoutMode diff --git a/core/java/android/webkit/ConsoleMessage.java b/core/java/android/webkit/ConsoleMessage.java index 5474557c9998..89cb6b2761be 100644 --- a/core/java/android/webkit/ConsoleMessage.java +++ b/core/java/android/webkit/ConsoleMessage.java @@ -68,4 +68,4 @@ public class ConsoleMessage { public int lineNumber() { return mLineNumber; } -}; +} diff --git a/core/java/android/webkit/ValueCallback.java b/core/java/android/webkit/ValueCallback.java index 5c7d97fc5d8c..3d5bb4922a77 100644 --- a/core/java/android/webkit/ValueCallback.java +++ b/core/java/android/webkit/ValueCallback.java @@ -25,4 +25,4 @@ public interface ValueCallback<T> { * @param value The value. */ public void onReceiveValue(T value); -}; +} diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java index db15145b0a1e..e62d5c95a1f8 100644 --- a/core/java/android/window/TransitionFilter.java +++ b/core/java/android/window/TransitionFilter.java @@ -296,7 +296,7 @@ public final class TransitionFilter implements Parcelable { out.append((i == 0 ? "" : ",") + TransitionInfo.modeToString(mModes[i])); } } - out.append("]").toString(); + out.append("]"); out.append(" flags=" + TransitionInfo.flagsToString(mFlags)); out.append(" mustBeTask=" + mMustBeTask); out.append(" order=" + containerOrderToString(mOrder)); diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index 30da4b470ab6..88447daf7338 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -58,11 +58,12 @@ interface IAppOpsService { SyncNotedAppOp noteProxyOperation(int code, in AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation); - SyncNotedAppOp startProxyOperation(int code, in AttributionSource attributionSource, - boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, - boolean shouldCollectMessage, boolean skipProxyOperation, int proxyAttributionFlags, - int proxiedAttributionFlags, int attributionChainId); - void finishProxyOperation(int code, in AttributionSource attributionSource, + SyncNotedAppOp startProxyOperation(IBinder clientId, int code, + in AttributionSource attributionSource, boolean startIfModeDefault, + boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, + boolean skipProxyOperation, int proxyAttributionFlags, int proxiedAttributionFlags, + int attributionChainId); + void finishProxyOperation(IBinder clientId, int code, in AttributionSource attributionSource, boolean skipProxyOperation); // Remaining methods are only used in Java. diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java index 97f4b0fc8733..a21a84261ae0 100644 --- a/core/java/com/android/internal/app/procstats/AssociationState.java +++ b/core/java/com/android/internal/app/procstats/AssociationState.java @@ -59,6 +59,7 @@ public final class AssociationState { /** * The state of the source process of an association. */ + @SuppressWarnings("ParcelableCreator") public static final class SourceState implements Parcelable { private @NonNull final ProcessStats mProcessStats; private @Nullable final AssociationState mAssociationState; diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 0a29fc5285a5..eb62cb07ee68 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -735,7 +735,7 @@ public class BinderCallsStats implements BinderInternal.Observer { } protected boolean shouldRecordDetailedData() { - return mRandom.nextInt() % mPeriodicSamplingInterval == 0; + return mRandom.nextInt(mPeriodicSamplingInterval) == 0; } /** diff --git a/core/java/com/android/internal/os/BinderLatencyObserver.java b/core/java/com/android/internal/os/BinderLatencyObserver.java index e9d55db3a5b4..1276fb980799 100644 --- a/core/java/com/android/internal/os/BinderLatencyObserver.java +++ b/core/java/com/android/internal/os/BinderLatencyObserver.java @@ -236,7 +236,7 @@ public class BinderLatencyObserver { } protected boolean shouldKeepSample() { - return mRandom.nextInt() % mPeriodicSamplingInterval == 0; + return mRandom.nextInt(mPeriodicSamplingInterval) == 0; } /** Updates the sampling interval. */ diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java index 2805dccffe50..0645eb7f0835 100644 --- a/core/java/com/android/internal/os/LooperStats.java +++ b/core/java/com/android/internal/os/LooperStats.java @@ -290,7 +290,7 @@ public class LooperStats implements Looper.Observer { } protected boolean shouldCollectDetailedData() { - return ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0; + return ThreadLocalRandom.current().nextInt(mSamplingInterval) == 0; } private static class DispatchSession { diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java index 8fcb6d5514d4..4b7b91c74f94 100644 --- a/core/java/com/android/internal/util/LatencyTracker.java +++ b/core/java/com/android/internal/util/LatencyTracker.java @@ -468,7 +468,7 @@ public class LatencyTracker { boolean shouldSample; int traceThreshold; synchronized (mLock) { - shouldSample = ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0; + shouldSample = ThreadLocalRandom.current().nextInt(mSamplingInterval) == 0; traceThreshold = mTraceThresholdPerAction[action]; } diff --git a/core/java/com/android/internal/view/BaseSurfaceHolder.java b/core/java/com/android/internal/view/BaseSurfaceHolder.java index 32ce0fe1282b..1ae1307633bb 100644 --- a/core/java/com/android/internal/view/BaseSurfaceHolder.java +++ b/core/java/com/android/internal/view/BaseSurfaceHolder.java @@ -241,4 +241,4 @@ public abstract class BaseSurfaceHolder implements SurfaceHolder { mSurfaceFrame.right = width; mSurfaceFrame.bottom = height; } -}; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7ada5483b92b..196ea59fe0f4 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -6184,6 +6184,116 @@ android:label="@string/permlab_foregroundService" android:protectionLevel="normal|instant" /> + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "camera". + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" + android:description="@string/permdesc_foregroundServiceCamera" + android:label="@string/permlab_foregroundServiceCamera" + android:protectionLevel="normal|instant" /> + + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "connectedDevice". + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" + android:description="@string/permdesc_foregroundServiceConnectedDevice" + android:label="@string/permlab_foregroundServiceConnectedDevice" + android:protectionLevel="normal|instant" /> + + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "dataSync". + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" + android:description="@string/permdesc_foregroundServiceDataSync" + android:label="@string/permlab_foregroundServiceDataSync" + android:protectionLevel="normal|instant" /> + + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "location". + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" + android:description="@string/permdesc_foregroundServiceLocation" + android:label="@string/permlab_foregroundServiceLocation" + android:protectionLevel="normal|instant" /> + + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "mediaPlayback". + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" + android:description="@string/permdesc_foregroundServiceMediaPlayback" + android:label="@string/permlab_foregroundServiceMediaPlayback" + android:protectionLevel="normal|instant" /> + + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "mediaProjection". + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" + android:description="@string/permdesc_foregroundServiceMediaProjection" + android:label="@string/permlab_foregroundServiceMediaProjection" + android:protectionLevel="normal|instant" /> + + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "microphone". + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" + android:description="@string/permdesc_foregroundServiceMicrophone" + android:label="@string/permlab_foregroundServiceMicrophone" + android:protectionLevel="normal|instant" /> + + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "phoneCall". + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" + android:description="@string/permdesc_foregroundServicePhoneCall" + android:label="@string/permlab_foregroundServicePhoneCall" + android:protectionLevel="normal|instant" /> + + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "health". + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH" + android:description="@string/permdesc_foregroundServiceHealth" + android:label="@string/permlab_foregroundServiceHealth" + android:protectionLevel="normal|instant" /> + + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "remoteMessaging". + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING" + android:description="@string/permdesc_foregroundServiceRemoteMessaging" + android:label="@string/permlab_foregroundServiceRemoteMessaging" + android:protectionLevel="normal|instant" /> + + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "systemExempted". + Apps are allowed to use this type only in the use cases listed in + {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED}. + <p>Protection level: normal|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" + android:description="@string/permdesc_foregroundServiceSystemExempted" + android:label="@string/permlab_foregroundServiceSystemExempted" + android:protectionLevel="normal|instant" /> + + <!-- Allows a regular application to use {@link android.app.Service#startForeground + Service.startForeground} with the type "specialUse". + <p>Protection level: signature|appop|instant + --> + <permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" + android:description="@string/permdesc_foregroundServiceSpecialUse" + android:label="@string/permlab_foregroundServiceSpecialUse" + android:protectionLevel="signature|appop|instant" /> + <!-- @SystemApi Allows to access all app shortcuts. @hide --> <permission android:name="android.permission.ACCESS_SHORTCUTS" diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index eac2b9443631..607467abe24f 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1586,19 +1586,71 @@ together. --> <attr name="foregroundServiceType"> <!-- Data (photo, file, account) upload/download, backup/restore, import/export, fetch, - transfer over network between device and cloud. --> + transfer over network between device and cloud. + + <p>For apps with <code>targetSdkVersion</code> + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, this type should NOT + be used: calling + {@link android.app.Service#startForeground(int, android.app.Notification, int)} with + this type on devices running {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} + is still allowed, but calling it with this type on devices running future platform + releases may get a {@link android.app.ForegroundServiceTypeNotAllowedException}. + --> <flag name="dataSync" value="0x01" /> - <!-- Music, video, news or other media play. --> + <!-- Music, video, news or other media play. + + <p>For apps with <code>targetSdkVersion</code> + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, starting a foreground + service with this type will require permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_MEDIA_PLAYBACK}. + --> <flag name="mediaPlayback" value="0x02" /> <!-- Ongoing operations related to phone calls, video conferencing, - or similar interactive communication. --> + or similar interactive communication. + + <p>For apps with <code>targetSdkVersion</code> + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, starting a foreground + service with this type will require permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_PHONE_CALL} and + {@link android.Manifest.permission#MANAGE_OWN_CALLS}. + --> <flag name="phoneCall" value="0x04" /> - <!-- GPS, map, navigation location update. --> + <!-- GPS, map, navigation location update. + + <p>For apps with <code>targetSdkVersion</code> + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, starting a foreground + service with this type will require permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_LOCATION} and one of the + following permissions: + {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}, + {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. + --> <flag name="location" value="0x08" /> - <!-- Auto, bluetooth, TV or other devices connection, monitoring and interaction. --> + <!-- Auto, bluetooth, TV or other devices connection, monitoring and interaction. + + <p>For apps with <code>targetSdkVersion</code> + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, starting a foreground + service with this type will require permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_CONNECTED_DEVICE} and one of the + following permissions: + {@link android.Manifest.permission#BLUETOOTH_CONNECT}, + {@link android.Manifest.permission#CHANGE_NETWORK_STATE}, + {@link android.Manifest.permission#CHANGE_WIFI_STATE}, + {@link android.Manifest.permission#CHANGE_WIFI_MULTICAST_STATE}, + {@link android.Manifest.permission#NFC}, + {@link android.Manifest.permission#TRANSMIT_IR}, + or has been granted the access to one of the attached USB devices/accessories. + --> <flag name="connectedDevice" value="0x10" /> <!-- Managing a media projection session, e.g, for screen recording or taking - screenshots.--> + screenshots. + + <p>For apps with <code>targetSdkVersion</code> + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, starting a foreground + service with this type will require permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_MEDIA_PROJECTION}, and the user + must have allowed the screen capture request from this app. + --> <flag name="mediaProjection" value="0x20" /> <!-- Use the camera device or record video. @@ -1606,6 +1658,12 @@ and above, a foreground service will not be able to access the camera if this type is not specified in the manifest and in {@link android.app.Service#startForeground(int, android.app.Notification, int)}. + + <p>For apps with <code>targetSdkVersion</code> + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, starting a foreground + service with this type will require permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_CAMERA} and + {@link android.Manifest.permission#CAMERA}. --> <flag name="camera" value="0x40" /> <!--Use the microphone device or record audio. @@ -1614,8 +1672,48 @@ and above, a foreground service will not be able to access the microphone if this type is not specified in the manifest and in {@link android.app.Service#startForeground(int, android.app.Notification, int)}. + + <p>For apps with <code>targetSdkVersion</code> + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, starting a foreground + service with this type will require permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_MICROPHONE} and one of the + following permissions: + {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT}, + {@link android.Manifest.permission#RECORD_AUDIO}. --> <flag name="microphone" value="0x80" /> + <!--Health, wellness and fitness. + <p>Requires the app to hold the permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_HEALTH} and one of the following + permissions + {@link android.Manifest.permission#ACTIVITY_RECOGNITION}, + {@link android.Manifest.permission#BODY_SENSORS}, + {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS}. + --> + <flag name="health" value="0x100" /> + <!-- Messaging use cases which host local server to relay messages across devices. + <p>Requires the app to hold the permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_REMOTE_MESSAGING} in order to use + this type. + --> + <flag name="remoteMessaging" value="0x200" /> + <!-- The system exmpted foreground service use cases. + <p>Requires the app to hold the permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_SYSTEM_EXEMPTED} in order to use + this type. Apps are allowed to use this type only in the use cases listed in + {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED}. + --> + <flag name="systemExempted" value="0x400" /> + <!-- Use cases that can't be categorized into any other foreground service types, but also + can't use @link android.app.job.JobInfo.Builder} APIs. + See {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SPECIAL_USE} for the + best practice of the use of this type. + + <p>Requires the app to hold the permission + {@link android.Manifest.permission#FOREGROUND_SERVICE_SPECIAL_USE} in order to use + this type. + --> + <flag name="specialUse" value="0x40000000" /> </attr> <!-- Enable sampled memory bug detection in this process. diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index ac383e69e02e..932b24ec08c9 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2434,7 +2434,7 @@ <!-- The duration in milliseconds of the dream opening animation. --> <integer name="config_dreamOpenAnimationDuration">250</integer> <!-- The duration in milliseconds of the dream closing animation. --> - <integer name="config_dreamCloseAnimationDuration">100</integer> + <integer name="config_dreamCloseAnimationDuration">300</integer> <!-- Whether to dismiss the active dream when an activity is started. Doesn't apply to assistant activities (ACTIVITY_TYPE_ASSISTANT) --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 216975d2d2e6..7714082dcfc4 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1143,6 +1143,66 @@ <string name="permdesc_foregroundService">Allows the app to make use of foreground services.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServiceCamera">run foreground service with the type \"camera\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServiceCamera">Allows the app to make use of foreground services with the type \"camera\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServiceConnectedDevice">run foreground service with the type \"connectedDevice\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServiceConnectedDevice">Allows the app to make use of foreground services with the type \"connectedDevice\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServiceDataSync">run foreground service with the type \"dataSync\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServiceDataSync">Allows the app to make use of foreground services with the type \"dataSync\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServiceLocation">run foreground service with the type \"location\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServiceLocation">Allows the app to make use of foreground services with the type \"location\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServiceMediaPlayback">run foreground service with the type \"mediaPlayback\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServiceMediaPlayback">Allows the app to make use of foreground services with the type \"mediaPlayback\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServiceMediaProjection">run foreground service with the type \"mediaProjection\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServiceMediaProjection">Allows the app to make use of foreground services with the type \"mediaProjection\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServiceMicrophone">run foreground service with the type \"microphone\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServiceMicrophone">Allows the app to make use of foreground services with the type \"microphone\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServicePhoneCall">run foreground service with the type \"phoneCall\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServicePhoneCall">Allows the app to make use of foreground services with the type \"phoneCall\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServiceHealth">run foreground service with the type \"health\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServiceHealth">Allows the app to make use of foreground services with the type \"health\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServiceRemoteMessaging">run foreground service with the type \"remoteMessaging\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServiceRemoteMessaging">Allows the app to make use of foreground services with the type \"remoteMessaging\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServiceSystemExempted">run foreground service with the type \"systemExempted\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServiceSystemExempted">Allows the app to make use of foreground services with the type \"systemExempted\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_foregroundServiceSpecialUse">run foreground service with the type \"specialUse\"</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_foregroundServiceSpecialUse">Allows the app to make use of foreground services with the type \"specialUse\"</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_getPackageSize">measure app storage space</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_getPackageSize">Allows the app to retrieve its code, data, and cache sizes</string> diff --git a/core/tests/benchmarks/src/android/os/ParcelableBenchmark.java b/core/tests/benchmarks/src/android/os/ParcelableBenchmark.java index 1cf430205627..372bca4664a2 100644 --- a/core/tests/benchmarks/src/android/os/ParcelableBenchmark.java +++ b/core/tests/benchmarks/src/android/os/ParcelableBenchmark.java @@ -88,6 +88,7 @@ public class ParcelableBenchmark { } } + @SuppressWarnings("ParcelableCreator") @SuppressLint("ParcelCreator") private static class PointArray implements Parcelable { Rect mBounds = new Rect(); diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerPropertyTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerPropertyTests.java index d505492f3b80..86e958320a04 100644 --- a/core/tests/coretests/src/android/content/pm/PackageManagerPropertyTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerPropertyTests.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; import android.content.pm.PackageManager.Property; @@ -162,40 +163,30 @@ public class PackageManagerPropertyTests { @Test public void testProperty_invalidName() throws Exception { - try { + assertThrows(NullPointerException.class, () -> { final Property p = new Property(null, 1, "android", null); - fail("expected assertion error"); - } catch (AssertionError expected) { - } + }); } @Test public void testProperty_invalidType() throws Exception { - try { + assertThrows(IllegalArgumentException.class, () -> { final Property p = new Property("invalidTypeProperty", 0, "android", null); - fail("expected assertion error"); - } catch (AssertionError expected) { - } + }); - try { + assertThrows(IllegalArgumentException.class, () -> { final Property p = new Property("invalidTypeProperty", 6, "android", null); - fail("expected assertion error"); - } catch (AssertionError expected) { - } + }); - try { + assertThrows(IllegalArgumentException.class, () -> { final Property p = new Property("invalidTypeProperty", -1, "android", null); - fail("expected assertion error"); - } catch (AssertionError expected) { - } + }); } @Test public void testProperty_noPackageName() throws Exception { - try { + assertThrows(NullPointerException.class, () -> { final Property p = new Property(null, 1, null, null); - fail("expected assertion error"); - } catch (AssertionError expected) { - } + }); } } diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java index 00b3693c902b..bbf9f3c99402 100644 --- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java +++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java @@ -128,6 +128,7 @@ public class RemoteViewsTest { RemoteViews clone = child.clone(); } + @SuppressWarnings("ReturnValueIgnored") @Test public void clone_repeatedly() { RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test); @@ -485,6 +486,7 @@ public class RemoteViewsTest { } } + @SuppressWarnings("ReturnValueIgnored") @Test public void nestedAddViews() { RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test); @@ -509,6 +511,7 @@ public class RemoteViewsTest { parcelAndRecreate(views); } + @SuppressWarnings("ReturnValueIgnored") @Test public void nestedLandscapeViews() { RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test); diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java index 82b2bf4185e6..8207c9ee5ff3 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java @@ -1054,10 +1054,23 @@ public class BinderCallsStatsTest { super(new Injector() { public Random getRandomGenerator() { return new Random() { - int mCallCount = 0; + int mCallCount = -1; public int nextInt() { - return mCallCount++; + throw new IllegalStateException("Should not use nextInt()"); + } + + public int nextInt(int x) { + if (mCallCount == -1) { + // The tests are written such that they expect + // the first call to nextInt() to be on the first + // callEnded(). However, the BinderCallsStats + // constructor also calls nextInt(). Fake 0 being + // rolled twice. + mCallCount++; + return 0; + } + return (mCallCount++) % x; } }; } diff --git a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java index 5af7376dc132..7bd53b9d4fcc 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java @@ -98,7 +98,7 @@ public class BinderLatencyObserverTest { assertEquals(1, latencyHistograms.size()); LatencyDims dims = latencyHistograms.keySet().iterator().next(); assertEquals(binder.getClass(), dims.getBinderClass()); - assertEquals(1, dims.getTransactionCode()); + assertEquals(2, dims.getTransactionCode()); // the first nextInt() is in the constructor assertThat(latencyHistograms.get(dims)).asList().containsExactly(1, 0, 0, 0, 0).inOrder(); } @@ -313,11 +313,11 @@ public class BinderLatencyObserverTest { int mCallCount = 0; public int nextInt() { - return mCallCount++; + throw new IllegalStateException("Should not use nextInt()"); } public int nextInt(int x) { - return 1; + return (mCallCount++) % x; } }; } diff --git a/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java b/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java index 6c50bce86638..8b30828a8936 100644 --- a/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java +++ b/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java @@ -16,6 +16,8 @@ package com.android.internal.util; +import static org.junit.Assert.assertThrows; + import android.os.SystemClock; import android.text.format.DateUtils; @@ -170,10 +172,9 @@ public class TokenBucketTest extends TestCase { } void assertThrow(Fn fn) { - try { + assertThrows(Throwable.class, () -> { fn.call(); - fail("expected n exception to be thrown."); - } catch (Throwable t) { } + }); } interface Fn { void call(); } diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java index 41b8956f55d0..a2263256508b 100644 --- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java +++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java @@ -31,6 +31,7 @@ public class Test extends ActivityInstrumentationTestCase2<MainActivity> { assertEquals(3366, getActivity().getValue()); } + @SuppressWarnings("ReturnValueIgnored") public void testAnnotation() throws Exception { assertEquals(ReferencedByAnnotation.B, ((AnnotationWithEnum) TestApplication.annotation).value()); diff --git a/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java b/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java index c53f4cc7ee52..1581abb5a9c6 100644 --- a/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java +++ b/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java @@ -20,6 +20,7 @@ import junit.framework.TestCase; import org.junit.Test; import java.util.ArrayList; +import java.util.Objects; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -39,11 +40,11 @@ public class CallbackRegistryTest extends TestCase { Integer argValue; private void addNotifyCount(Integer callback) { - if (callback == callback1) { + if (Objects.equals(callback, callback1)) { notify1++; - } else if (callback == callback2) { + } else if (Objects.equals(callback, callback2)) { notify2++; - } else if (callback == callback3) { + } else if (Objects.equals(callback, callback3)) { notify3++; } deepNotifyCount[callback]++; @@ -114,7 +115,7 @@ public class CallbackRegistryTest extends TestCase { public void onNotifyCallback(Integer callback, CallbackRegistryTest sender, int arg1, Integer arg) { addNotifyCount(callback); - if (callback == callback1) { + if (Objects.equals(callback, callback1)) { registry.remove(callback1); registry.remove(callback2); } @@ -166,9 +167,9 @@ public class CallbackRegistryTest extends TestCase { public void onNotifyCallback(Integer callback, CallbackRegistryTest sender, int arg1, Integer arg) { addNotifyCount(callback); - if (callback == callback1) { + if (Objects.equals(callback, callback1)) { registry.remove(callback2); - } else if (callback == callback3) { + } else if (Objects.equals(callback, callback3)) { registry.add(callback2); } } diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index decfb9fc59df..3e2b71f18b75 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -495,6 +495,10 @@ applications that come with the platform <permission name="android.permission.READ_SAFETY_CENTER_STATUS" /> <!-- Permission required for CTS test - CtsTelephonyTestCases --> <permission name="android.permission.BIND_TELECOM_CONNECTION_SERVICE" /> + <!-- Permission required for CTS test - CtsAppTestCases --> + <permission name="android.permission.CAPTURE_MEDIA_OUTPUT" /> + <permission name="android.permission.CAPTURE_TUNER_AUDIO_INPUT" /> + <permission name="android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientXmlChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientXmlChecker.java index 8706a68226ef..42e304699cd4 100644 --- a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientXmlChecker.java +++ b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientXmlChecker.java @@ -168,6 +168,7 @@ public final class EfficientXmlChecker extends BugChecker */ private static final Matcher<ExpressionTree> CONVERT_PRIMITIVE_TO_STRING = new Matcher<ExpressionTree>() { + @SuppressWarnings("TreeToString") //TODO: Fix me @Override public boolean matches(ExpressionTree tree, VisitorState state) { if (PRIMITIVE_TO_STRING.matches(tree, state)) { @@ -205,6 +206,7 @@ public final class EfficientXmlChecker extends BugChecker */ private static final Matcher<ExpressionTree> CONVERT_STRING_TO_PRIMITIVE = new Matcher<ExpressionTree>() { + @SuppressWarnings("TreeToString") //TODO: Fix me @Override public boolean matches(ExpressionTree tree, VisitorState state) { if (PRIMITIVE_PARSE.matches(tree, state)) { diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 54c9f6222f7e..1a878dfa2cf2 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -766,7 +766,7 @@ public class RippleDrawable extends LayerDrawable { if (mBackground != null) { mBackground.onHotspotBoundsChanged(); } - float newRadius = Math.round(getComputedRadius()); + float newRadius = getComputedRadius(); for (int i = 0; i < mRunningAnimations.size(); i++) { RippleAnimationSession s = mRunningAnimations.get(i); s.setRadius(newRadius); diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index 4065bd110c7e..e25ee906b410 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -60,7 +60,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Map; import java.util.Stack; /** @@ -1171,18 +1171,14 @@ public class VectorDrawable extends Drawable { private static final int NATIVE_ALLOCATION_SIZE = 100; - private static final HashMap<String, Integer> sPropertyIndexMap = - new HashMap<String, Integer>() { - { - put("translateX", TRANSLATE_X_INDEX); - put("translateY", TRANSLATE_Y_INDEX); - put("scaleX", SCALE_X_INDEX); - put("scaleY", SCALE_Y_INDEX); - put("pivotX", PIVOT_X_INDEX); - put("pivotY", PIVOT_Y_INDEX); - put("rotation", ROTATION_INDEX); - } - }; + private static final Map<String, Integer> sPropertyIndexMap = Map.of( + "translateX", TRANSLATE_X_INDEX, + "translateY", TRANSLATE_Y_INDEX, + "scaleX", SCALE_X_INDEX, + "scaleY", SCALE_Y_INDEX, + "pivotX", PIVOT_X_INDEX, + "pivotY", PIVOT_Y_INDEX, + "rotation", ROTATION_INDEX); static int getPropertyIndex(String propertyName) { if (sPropertyIndexMap.containsKey(propertyName)) { @@ -1285,18 +1281,15 @@ public class VectorDrawable extends Drawable { } }; - private static final HashMap<String, Property> sPropertyMap = - new HashMap<String, Property>() { - { - put("translateX", TRANSLATE_X); - put("translateY", TRANSLATE_Y); - put("scaleX", SCALE_X); - put("scaleY", SCALE_Y); - put("pivotX", PIVOT_X); - put("pivotY", PIVOT_Y); - put("rotation", ROTATION); - } - }; + private static final Map<String, Property> sPropertyMap = Map.of( + "translateX", TRANSLATE_X, + "translateY", TRANSLATE_Y, + "scaleX", SCALE_X, + "scaleY", SCALE_Y, + "pivotX", PIVOT_X, + "pivotY", PIVOT_Y, + "rotation", ROTATION); + // Temp array to store transform values obtained from native. private float[] mTransform; ///////////////////////////////////////////////////// @@ -1762,19 +1755,15 @@ public class VectorDrawable extends Drawable { private static final int NATIVE_ALLOCATION_SIZE = 264; // Property map for animatable attributes. - private final static HashMap<String, Integer> sPropertyIndexMap - = new HashMap<String, Integer> () { - { - put("strokeWidth", STROKE_WIDTH_INDEX); - put("strokeColor", STROKE_COLOR_INDEX); - put("strokeAlpha", STROKE_ALPHA_INDEX); - put("fillColor", FILL_COLOR_INDEX); - put("fillAlpha", FILL_ALPHA_INDEX); - put("trimPathStart", TRIM_PATH_START_INDEX); - put("trimPathEnd", TRIM_PATH_END_INDEX); - put("trimPathOffset", TRIM_PATH_OFFSET_INDEX); - } - }; + private static final Map<String, Integer> sPropertyIndexMap = Map.of( + "strokeWidth", STROKE_WIDTH_INDEX, + "strokeColor", STROKE_COLOR_INDEX, + "strokeAlpha", STROKE_ALPHA_INDEX, + "fillColor", FILL_COLOR_INDEX, + "fillAlpha", FILL_ALPHA_INDEX, + "trimPathStart", TRIM_PATH_START_INDEX, + "trimPathEnd", TRIM_PATH_END_INDEX, + "trimPathOffset", TRIM_PATH_OFFSET_INDEX); // Below are the Properties that wrap the setters to avoid reflection overhead in animations private static final Property<VFullPath, Float> STROKE_WIDTH = @@ -1881,19 +1870,15 @@ public class VectorDrawable extends Drawable { } }; - private final static HashMap<String, Property> sPropertyMap - = new HashMap<String, Property> () { - { - put("strokeWidth", STROKE_WIDTH); - put("strokeColor", STROKE_COLOR); - put("strokeAlpha", STROKE_ALPHA); - put("fillColor", FILL_COLOR); - put("fillAlpha", FILL_ALPHA); - put("trimPathStart", TRIM_PATH_START); - put("trimPathEnd", TRIM_PATH_END); - put("trimPathOffset", TRIM_PATH_OFFSET); - } - }; + private static final Map<String, Property> sPropertyMap = Map.of( + "strokeWidth", STROKE_WIDTH, + "strokeColor", STROKE_COLOR, + "strokeAlpha", STROKE_ALPHA, + "fillColor", FILL_COLOR, + "fillAlpha", FILL_ALPHA, + "trimPathStart", TRIM_PATH_START, + "trimPathEnd", TRIM_PATH_END, + "trimPathOffset", TRIM_PATH_OFFSET); // Temp array to store property data obtained from native getter. private byte[] mPropertyData; diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index a7fa2d936940..16760e26b3f1 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -96,7 +96,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen ActivityEmbeddingComponent { static final String TAG = "SplitController"; static final boolean ENABLE_SHELL_TRANSITIONS = - SystemProperties.getBoolean("persist.wm.debug.shell_transit", true); + SystemProperties.getBoolean("persist.wm.debug.shell_transit", false); @VisibleForTesting @GuardedBy("mLock") diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index d9eaeeeaf45f..07cd7d6f60b7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -611,8 +611,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mBackAnimationFinishedCallback = finishedCallback; ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: startAnimation()"); - runner.startAnimation(apps, wallpapers, nonApps, - BackAnimationController.this::onBackAnimationFinished); + runner.startAnimation(apps, wallpapers, nonApps, () -> mShellExecutor.execute( + BackAnimationController.this::onBackAnimationFinished)); if (apps.length >= 1) { dispatchOnBackStarted( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index c6f31c23ff25..56d51bda762f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -80,7 +80,7 @@ public class Transitions implements RemoteCallable<Transitions> { /** Set to {@code true} to enable shell transitions. */ public static final boolean ENABLE_SHELL_TRANSITIONS = - SystemProperties.getBoolean("persist.wm.debug.shell_transit", true); + SystemProperties.getBoolean("persist.wm.debug.shell_transit", false); public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS && SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index ca15f0002fac..ebe5c5e716d7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -124,7 +124,8 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { TaskPositioner taskPositioner = new TaskPositioner(mTaskOrganizer, windowDecoration, mDragStartListener); CaptionTouchEventListener touchEventListener = - new CaptionTouchEventListener(taskInfo, taskPositioner); + new CaptionTouchEventListener(taskInfo, taskPositioner, + windowDecoration.getDragDetector()); windowDecoration.setCaptionListeners(touchEventListener, touchEventListener); windowDecoration.setDragResizeCallback(taskPositioner); setupWindowDecorationForTransition(taskInfo, startT, finishT); @@ -173,16 +174,18 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { private final int mTaskId; private final WindowContainerToken mTaskToken; private final DragResizeCallback mDragResizeCallback; + private final DragDetector mDragDetector; private int mDragPointerId = -1; - private boolean mDragActive = false; private CaptionTouchEventListener( RunningTaskInfo taskInfo, - DragResizeCallback dragResizeCallback) { + DragResizeCallback dragResizeCallback, + DragDetector dragDetector) { mTaskId = taskInfo.taskId; mTaskToken = taskInfo.token; mDragResizeCallback = dragResizeCallback; + mDragDetector = dragDetector; } @Override @@ -231,19 +234,21 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { @Override public boolean onTouch(View v, MotionEvent e) { + boolean isDrag = false; int id = v.getId(); if (id != R.id.caption_handle && id != R.id.caption) { return false; } - if (id == R.id.caption_handle || mDragActive) { + if (id == R.id.caption_handle) { + isDrag = mDragDetector.detectDragEvent(e); handleEventForMove(e); } if (e.getAction() != MotionEvent.ACTION_DOWN) { - return false; + return isDrag; } RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); if (taskInfo.isFocused) { - return false; + return isDrag; } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.reorder(mTaskToken, true /* onTop */); @@ -251,6 +256,10 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { return true; } + /** + * @param e {@link MotionEvent} to process + * @return {@code true} if a drag is happening; or {@code false} if it is not + */ private void handleEventForMove(MotionEvent e) { RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); int windowingMode = mDesktopModeController @@ -259,12 +268,12 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { return; } switch (e.getActionMasked()) { - case MotionEvent.ACTION_DOWN: - mDragActive = true; - mDragPointerId = e.getPointerId(0); + case MotionEvent.ACTION_DOWN: { + mDragPointerId = e.getPointerId(0); mDragResizeCallback.onDragResizeStart( 0 /* ctrlType */, e.getRawX(0), e.getRawY(0)); break; + } case MotionEvent.ACTION_MOVE: { int dragPointerIdx = e.findPointerIndex(mDragPointerId); mDragResizeCallback.onDragResizeMove( @@ -273,7 +282,6 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { - mDragActive = false; int dragPointerIdx = e.findPointerIndex(mDragPointerId); int statusBarHeight = mDisplayController.getDisplayLayout(taskInfo.displayId) .stableInsets().top; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java index 03cad043ed67..affde3009456 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java @@ -62,6 +62,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL private boolean mDesktopActive; + private DragDetector mDragDetector; + private AdditionalWindow mHandleMenu; CaptionWindowDecoration( @@ -79,6 +81,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL mChoreographer = choreographer; mSyncQueue = syncQueue; mDesktopActive = DesktopModeStatus.isActive(mContext); + mDragDetector = new DragDetector(ViewConfiguration.get(context).getScaledTouchSlop()); } void setCaptionListeners( @@ -92,6 +95,10 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL mDragResizeCallback = dragResizeCallback; } + DragDetector getDragDetector() { + return mDragDetector; + } + @Override void relayout(ActivityManager.RunningTaskInfo taskInfo) { final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); @@ -182,6 +189,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL } int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()).getScaledTouchSlop(); + mDragDetector.setTouchSlop(touchSlop); + int resize_handle = mResult.mRootView.getResources() .getDimensionPixelSize(R.dimen.freeform_resize_handle); int resize_corner = mResult.mRootView.getResources() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java new file mode 100644 index 000000000000..0abe8ab2e30b --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.windowdecor; + +import static android.view.MotionEvent.ACTION_CANCEL; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_MOVE; +import static android.view.MotionEvent.ACTION_UP; + +import android.graphics.PointF; +import android.view.MotionEvent; + +/** + * A detector for touch inputs that differentiates between drag and click inputs. + * All touch events must be passed through this class to track a drag event. + */ +public class DragDetector { + private int mTouchSlop; + private PointF mInputDownPoint; + private boolean mIsDragEvent; + private int mDragPointerId; + public DragDetector(int touchSlop) { + mTouchSlop = touchSlop; + mInputDownPoint = new PointF(); + mIsDragEvent = false; + mDragPointerId = -1; + } + + /** + * Determine if {@link MotionEvent} is part of a drag event. + * @return {@code true} if this is a drag event, {@code false} if not + */ + public boolean detectDragEvent(MotionEvent ev) { + switch (ev.getAction()) { + case ACTION_DOWN: { + mDragPointerId = ev.getPointerId(0); + float rawX = ev.getRawX(0); + float rawY = ev.getRawY(0); + mInputDownPoint.set(rawX, rawY); + return false; + } + case ACTION_MOVE: { + if (!mIsDragEvent) { + int dragPointerIndex = ev.findPointerIndex(mDragPointerId); + float dx = ev.getRawX(dragPointerIndex) - mInputDownPoint.x; + float dy = ev.getRawY(dragPointerIndex) - mInputDownPoint.y; + if (Math.hypot(dx, dy) > mTouchSlop) { + mIsDragEvent = true; + } + } + return mIsDragEvent; + } + case ACTION_UP: { + boolean result = mIsDragEvent; + mIsDragEvent = false; + mInputDownPoint.set(0, 0); + mDragPointerId = -1; + return result; + } + case ACTION_CANCEL: { + mIsDragEvent = false; + mInputDownPoint.set(0, 0); + mDragPointerId = -1; + return false; + } + } + return mIsDragEvent; + } + + public void setTouchSlop(int touchSlop) { + mTouchSlop = touchSlop; + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java index b9f16b63de48..48c0cea150cc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java @@ -22,7 +22,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERL import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import android.content.Context; -import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; import android.hardware.input.InputManager; @@ -38,6 +37,7 @@ import android.view.InputEventReceiver; import android.view.MotionEvent; import android.view.PointerIcon; import android.view.SurfaceControl; +import android.view.ViewConfiguration; import android.view.WindowManagerGlobal; import com.android.internal.view.BaseIWindow; @@ -76,7 +76,7 @@ class DragResizeInputListener implements AutoCloseable { private Rect mRightBottomCornerBounds; private int mDragPointerId = -1; - private int mTouchSlop; + private DragDetector mDragDetector; DragResizeInputListener( Context context, @@ -115,6 +115,7 @@ class DragResizeInputListener implements AutoCloseable { mInputEventReceiver = new TaskResizeInputEventReceiver( mInputChannel, mHandler, mChoreographer); mCallback = callback; + mDragDetector = new DragDetector(ViewConfiguration.get(context).getScaledTouchSlop()); } /** @@ -146,7 +147,7 @@ class DragResizeInputListener implements AutoCloseable { mHeight = height; mResizeHandleThickness = resizeHandleThickness; mCornerSize = cornerSize; - mTouchSlop = touchSlop; + mDragDetector.setTouchSlop(touchSlop); Region touchRegion = new Region(); final Rect topInputBounds = new Rect(0, 0, mWidth, mResizeHandleThickness); @@ -228,7 +229,6 @@ class DragResizeInputListener implements AutoCloseable { private boolean mConsumeBatchEventScheduled; private boolean mShouldHandleEvents; private boolean mDragging; - private final PointF mActionDownPoint = new PointF(); private TaskResizeInputEventReceiver( InputChannel inputChannel, Handler handler, Choreographer choreographer) { @@ -276,7 +276,9 @@ class DragResizeInputListener implements AutoCloseable { // Check if this is a touch event vs mouse event. // Touch events are tracked in four corners. Other events are tracked in resize edges. boolean isTouch = (e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN; - + if (isTouch) { + mDragging = mDragDetector.detectDragEvent(e); + } switch (e.getActionMasked()) { case MotionEvent.ACTION_DOWN: { float x = e.getX(0); @@ -290,7 +292,6 @@ class DragResizeInputListener implements AutoCloseable { mDragPointerId = e.getPointerId(0); float rawX = e.getRawX(0); float rawY = e.getRawY(0); - mActionDownPoint.set(rawX, rawY); int ctrlType = calculateCtrlType(isTouch, x, y); mCallback.onDragResizeStart(ctrlType, rawX, rawY); result = true; @@ -304,14 +305,7 @@ class DragResizeInputListener implements AutoCloseable { int dragPointerIndex = e.findPointerIndex(mDragPointerId); float rawX = e.getRawX(dragPointerIndex); float rawY = e.getRawY(dragPointerIndex); - if (isTouch) { - // Check for touch slop for touch events - float dx = rawX - mActionDownPoint.x; - float dy = rawY - mActionDownPoint.y; - if (!mDragging && Math.hypot(dx, dy) > mTouchSlop) { - mDragging = true; - } - } else { + if (!isTouch) { // For all other types allow immediate dragging. mDragging = true; } @@ -330,7 +324,6 @@ class DragResizeInputListener implements AutoCloseable { } mDragging = false; mShouldHandleEvents = false; - mActionDownPoint.set(0, 0); mDragPointerId = -1; result = true; break; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java index 1a1bebd28aef..5ee8bf3006a3 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java @@ -61,7 +61,7 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public final class StageTaskListenerTests extends ShellTestCase { private static final boolean ENABLE_SHELL_TRANSITIONS = - SystemProperties.getBoolean("persist.wm.debug.shell_transit", true); + SystemProperties.getBoolean("persist.wm.debug.shell_transit", false); @Mock private ShellTaskOrganizer mTaskOrganizer; diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java index 4f45602276b5..a6da0a301309 100644 --- a/location/java/android/location/GnssCapabilities.java +++ b/location/java/android/location/GnssCapabilities.java @@ -25,6 +25,7 @@ import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; @@ -125,7 +126,7 @@ public final class GnssCapabilities implements Parcelable { * @hide */ public static GnssCapabilities empty() { - return new GnssCapabilities(0, 0, 0, new ArrayList<>()); + return new GnssCapabilities(0, 0, 0, Collections.emptyList()); } private final @TopHalCapabilityFlags int mTopFlags; @@ -142,7 +143,7 @@ public final class GnssCapabilities implements Parcelable { mTopFlags = topFlags; mMeasurementCorrectionsFlags = measurementCorrectionsFlags; mPowerFlags = powerFlags; - mGnssSignalTypes = gnssSignalTypes; + mGnssSignalTypes = Collections.unmodifiableList(gnssSignalTypes); } /** @@ -155,7 +156,7 @@ public final class GnssCapabilities implements Parcelable { return this; } else { return new GnssCapabilities(flags, mMeasurementCorrectionsFlags, mPowerFlags, - new ArrayList<>(mGnssSignalTypes)); + mGnssSignalTypes); } } @@ -171,7 +172,7 @@ public final class GnssCapabilities implements Parcelable { return this; } else { return new GnssCapabilities(mTopFlags, flags, mPowerFlags, - new ArrayList<>(mGnssSignalTypes)); + mGnssSignalTypes); } } @@ -186,7 +187,7 @@ public final class GnssCapabilities implements Parcelable { return this; } else { return new GnssCapabilities(mTopFlags, mMeasurementCorrectionsFlags, flags, - new ArrayList<>(mGnssSignalTypes)); + mGnssSignalTypes); } } @@ -606,7 +607,7 @@ public final class GnssCapabilities implements Parcelable { mTopFlags = 0; mMeasurementCorrectionsFlags = 0; mPowerFlags = 0; - mGnssSignalTypes = new ArrayList<>(); + mGnssSignalTypes = Collections.emptyList(); } public Builder(@NonNull GnssCapabilities capabilities) { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index d975e96f193b..17d7045eacaf 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -2328,10 +2328,9 @@ public class AudioManager { return AudioSystem.SUCCESS; } - private final Map<Integer, Object> mDevRoleForCapturePresetListeners = new HashMap<>(){{ - put(AudioSystem.DEVICE_ROLE_PREFERRED, - new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>()); - }}; + private final Map<Integer, Object> mDevRoleForCapturePresetListeners = Map.of( + AudioSystem.DEVICE_ROLE_PREFERRED, + new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>()); private class DevRoleListenerInfo<T> { final @NonNull Executor mExecutor; @@ -6515,15 +6514,17 @@ public class AudioManager { // AudioPort implementation // - static final int AUDIOPORT_GENERATION_INIT = 0; - static Integer sAudioPortGeneration = new Integer(AUDIOPORT_GENERATION_INIT); - static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>(); - static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>(); - static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>(); + private static final int AUDIOPORT_GENERATION_INIT = 0; + private static Object sAudioPortGenerationLock = new Object(); + @GuardedBy("sAudioPortGenerationLock") + private static int sAudioPortGeneration = AUDIOPORT_GENERATION_INIT; + private static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>(); + private static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>(); + private static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>(); static int resetAudioPortGeneration() { int generation; - synchronized (sAudioPortGeneration) { + synchronized (sAudioPortGenerationLock) { generation = sAudioPortGeneration; sAudioPortGeneration = AUDIOPORT_GENERATION_INIT; } @@ -6533,7 +6534,7 @@ public class AudioManager { static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, ArrayList<AudioPort> previousPorts) { sAudioPortEventHandler.init(); - synchronized (sAudioPortGeneration) { + synchronized (sAudioPortGenerationLock) { if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) { int[] patchGeneration = new int[1]; diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java index ca175b4853a6..0f962f9e9d4b 100644 --- a/media/java/android/media/AudioMetadata.java +++ b/media/java/android/media/AudioMetadata.java @@ -30,6 +30,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -446,14 +447,13 @@ public final class AudioMetadata { // BaseMap is corresponding to audio_utils::metadata::Data private static final int AUDIO_METADATA_OBJ_TYPE_BASEMAP = 6; - private static final HashMap<Class, Integer> AUDIO_METADATA_OBJ_TYPES = new HashMap<>() {{ - put(Integer.class, AUDIO_METADATA_OBJ_TYPE_INT); - put(Long.class, AUDIO_METADATA_OBJ_TYPE_LONG); - put(Float.class, AUDIO_METADATA_OBJ_TYPE_FLOAT); - put(Double.class, AUDIO_METADATA_OBJ_TYPE_DOUBLE); - put(String.class, AUDIO_METADATA_OBJ_TYPE_STRING); - put(BaseMap.class, AUDIO_METADATA_OBJ_TYPE_BASEMAP); - }}; + private static final Map<Class, Integer> AUDIO_METADATA_OBJ_TYPES = Map.of( + Integer.class, AUDIO_METADATA_OBJ_TYPE_INT, + Long.class, AUDIO_METADATA_OBJ_TYPE_LONG, + Float.class, AUDIO_METADATA_OBJ_TYPE_FLOAT, + Double.class, AUDIO_METADATA_OBJ_TYPE_DOUBLE, + String.class, AUDIO_METADATA_OBJ_TYPE_STRING, + BaseMap.class, AUDIO_METADATA_OBJ_TYPE_BASEMAP); private static final Charset AUDIO_METADATA_CHARSET = StandardCharsets.UTF_8; @@ -634,8 +634,8 @@ public final class AudioMetadata { * Datum corresponds to Object ****************************************************************************************/ - private static final HashMap<Integer, DataPackage<?>> DATA_PACKAGES = new HashMap<>() {{ - put(AUDIO_METADATA_OBJ_TYPE_INT, new DataPackage<Integer>() { + private static final Map<Integer, DataPackage<?>> DATA_PACKAGES = Map.of( + AUDIO_METADATA_OBJ_TYPE_INT, new DataPackage<Integer>() { @Override @Nullable public Integer unpack(ByteBuffer buffer) { @@ -647,8 +647,8 @@ public final class AudioMetadata { output.putInt(obj); return true; } - }); - put(AUDIO_METADATA_OBJ_TYPE_LONG, new DataPackage<Long>() { + }, + AUDIO_METADATA_OBJ_TYPE_LONG, new DataPackage<Long>() { @Override @Nullable public Long unpack(ByteBuffer buffer) { @@ -660,8 +660,8 @@ public final class AudioMetadata { output.putLong(obj); return true; } - }); - put(AUDIO_METADATA_OBJ_TYPE_FLOAT, new DataPackage<Float>() { + }, + AUDIO_METADATA_OBJ_TYPE_FLOAT, new DataPackage<Float>() { @Override @Nullable public Float unpack(ByteBuffer buffer) { @@ -673,8 +673,8 @@ public final class AudioMetadata { output.putFloat(obj); return true; } - }); - put(AUDIO_METADATA_OBJ_TYPE_DOUBLE, new DataPackage<Double>() { + }, + AUDIO_METADATA_OBJ_TYPE_DOUBLE, new DataPackage<Double>() { @Override @Nullable public Double unpack(ByteBuffer buffer) { @@ -686,8 +686,8 @@ public final class AudioMetadata { output.putDouble(obj); return true; } - }); - put(AUDIO_METADATA_OBJ_TYPE_STRING, new DataPackage<String>() { + }, + AUDIO_METADATA_OBJ_TYPE_STRING, new DataPackage<String>() { @Override @Nullable public String unpack(ByteBuffer buffer) { @@ -713,9 +713,9 @@ public final class AudioMetadata { output.put(valueArr); return true; } - }); - put(AUDIO_METADATA_OBJ_TYPE_BASEMAP, new BaseMapPackage()); - }}; + }, + AUDIO_METADATA_OBJ_TYPE_BASEMAP, new BaseMapPackage()); + // ObjectPackage is a special case that it is expected to unpack audio_utils::metadata::Datum, // which contains data type and data size besides the payload for the data. private static final ObjectPackage OBJECT_PACKAGE = new ObjectPackage(); diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 85cd342b5e11..d51f1e1327bd 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -48,8 +48,8 @@ import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.NioUtils; -import java.util.HashMap; import java.util.LinkedList; +import java.util.Map; import java.util.Objects; import java.util.concurrent.Executor; @@ -1867,26 +1867,24 @@ public class AudioTrack extends PlayerBase } // General pair map - private static final HashMap<String, Integer> CHANNEL_PAIR_MAP = new HashMap<>() {{ - put("front", AudioFormat.CHANNEL_OUT_FRONT_LEFT - | AudioFormat.CHANNEL_OUT_FRONT_RIGHT); - put("back", AudioFormat.CHANNEL_OUT_BACK_LEFT - | AudioFormat.CHANNEL_OUT_BACK_RIGHT); - put("front of center", AudioFormat.CHANNEL_OUT_FRONT_LEFT_OF_CENTER - | AudioFormat.CHANNEL_OUT_FRONT_RIGHT_OF_CENTER); - put("side", AudioFormat.CHANNEL_OUT_SIDE_LEFT - | AudioFormat.CHANNEL_OUT_SIDE_RIGHT); - put("top front", AudioFormat.CHANNEL_OUT_TOP_FRONT_LEFT - | AudioFormat.CHANNEL_OUT_TOP_FRONT_RIGHT); - put("top back", AudioFormat.CHANNEL_OUT_TOP_BACK_LEFT - | AudioFormat.CHANNEL_OUT_TOP_BACK_RIGHT); - put("top side", AudioFormat.CHANNEL_OUT_TOP_SIDE_LEFT - | AudioFormat.CHANNEL_OUT_TOP_SIDE_RIGHT); - put("bottom front", AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_LEFT - | AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_RIGHT); - put("front wide", AudioFormat.CHANNEL_OUT_FRONT_WIDE_LEFT - | AudioFormat.CHANNEL_OUT_FRONT_WIDE_RIGHT); - }}; + private static final Map<String, Integer> CHANNEL_PAIR_MAP = Map.of( + "front", AudioFormat.CHANNEL_OUT_FRONT_LEFT + | AudioFormat.CHANNEL_OUT_FRONT_RIGHT, + "back", AudioFormat.CHANNEL_OUT_BACK_LEFT + | AudioFormat.CHANNEL_OUT_BACK_RIGHT, + "front of center", AudioFormat.CHANNEL_OUT_FRONT_LEFT_OF_CENTER + | AudioFormat.CHANNEL_OUT_FRONT_RIGHT_OF_CENTER, + "side", AudioFormat.CHANNEL_OUT_SIDE_LEFT | AudioFormat.CHANNEL_OUT_SIDE_RIGHT, + "top front", AudioFormat.CHANNEL_OUT_TOP_FRONT_LEFT + | AudioFormat.CHANNEL_OUT_TOP_FRONT_RIGHT, + "top back", AudioFormat.CHANNEL_OUT_TOP_BACK_LEFT + | AudioFormat.CHANNEL_OUT_TOP_BACK_RIGHT, + "top side", AudioFormat.CHANNEL_OUT_TOP_SIDE_LEFT + | AudioFormat.CHANNEL_OUT_TOP_SIDE_RIGHT, + "bottom front", AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_LEFT + | AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_RIGHT, + "front wide", AudioFormat.CHANNEL_OUT_FRONT_WIDE_LEFT + | AudioFormat.CHANNEL_OUT_FRONT_WIDE_RIGHT); /** * Convenience method to check that the channel configuration (a.k.a channel mask) is supported @@ -1924,7 +1922,7 @@ public class AudioTrack extends PlayerBase return false; } // Check all pairs to see that they are matched (front duplicated here). - for (HashMap.Entry<String, Integer> e : CHANNEL_PAIR_MAP.entrySet()) { + for (Map.Entry<String, Integer> e : CHANNEL_PAIR_MAP.entrySet()) { final int positionPair = e.getValue(); if ((channelConfig & positionPair) != 0 && (channelConfig & positionPair) != positionPair) { diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index 0c8cacd894cf..524bde4e7d15 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -70,6 +70,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TimeZone; import java.util.regex.Matcher; @@ -4836,12 +4837,13 @@ public class ExifInterface { for (int i = 1; i < entryValues.length; ++i) { final Pair<Integer, Integer> guessDataFormat = guessDataFormat(entryValues[i]); int first = -1, second = -1; - if (guessDataFormat.first == dataFormat.first - || guessDataFormat.second == dataFormat.first) { + if (Objects.equals(guessDataFormat.first, dataFormat.first) + || Objects.equals(guessDataFormat.second, dataFormat.first)) { first = dataFormat.first; } - if (dataFormat.second != -1 && (guessDataFormat.first == dataFormat.second - || guessDataFormat.second == dataFormat.second)) { + if (dataFormat.second != -1 + && (Objects.equals(guessDataFormat.first, dataFormat.second) + || Objects.equals(guessDataFormat.second, dataFormat.second))) { second = dataFormat.second; } if (first == -1 && second == -1) { diff --git a/media/java/android/media/MediaHTTPService.java b/media/java/android/media/MediaHTTPService.java index 3008067daefb..2342a426e77c 100644 --- a/media/java/android/media/MediaHTTPService.java +++ b/media/java/android/media/MediaHTTPService.java @@ -21,6 +21,8 @@ import android.compat.annotation.UnsupportedAppUsage; import android.os.IBinder; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + import java.net.CookieHandler; import java.net.CookieManager; import java.net.CookieStore; @@ -31,7 +33,9 @@ import java.util.List; public class MediaHTTPService extends IMediaHTTPService.Stub { private static final String TAG = "MediaHTTPService"; @Nullable private List<HttpCookie> mCookies; - private Boolean mCookieStoreInitialized = new Boolean(false); + private final Object mCookieStoreInitializedLock = new Object(); + @GuardedBy("mCookieStoreInitializedLock") + private boolean mCookieStoreInitialized = false; public MediaHTTPService(@Nullable List<HttpCookie> cookies) { mCookies = cookies; @@ -40,7 +44,7 @@ public class MediaHTTPService extends IMediaHTTPService.Stub { public IMediaHTTPConnection makeHTTPConnection() { - synchronized (mCookieStoreInitialized) { + synchronized (mCookieStoreInitializedLock) { // Only need to do it once for all connections if ( !mCookieStoreInitialized ) { CookieHandler cookieHandler = CookieHandler.getDefault(); @@ -78,8 +82,8 @@ public class MediaHTTPService extends IMediaHTTPService.Stub { Log.v(TAG, "makeHTTPConnection(" + this + "): cookieHandler: " + cookieHandler + " Cookies: " + mCookies); - } // mCookieStoreInitialized - } // synchronized + } + } return new MediaHTTPConnection(); } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 77b574695ede..79a59023a1b3 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -2507,6 +2507,8 @@ public class MediaPlayer extends PlayerBase * * @see android.media.MediaPlayer#getTrackInfo */ + // The creator needs to be pulic, which requires removing the @UnsupportedAppUsage + @SuppressWarnings("ParcelableCreator") static public class TrackInfo implements Parcelable { /** * Gets the track type. diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl index 84b9c9ebfc18..38fc71711f7d 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl @@ -64,6 +64,7 @@ interface ITvInteractiveAppManager { void notifyContentBlocked(in IBinder sessionToken, in String rating, int userId); void notifySignalStrength(in IBinder sessionToken, int stength, int userId); void notifyRecordingStarted(in IBinder sessionToken, in String recordingId, int userId); + void notifyRecordingStopped(in IBinder sessionToken, in String recordingId, int userId); void setSurface(in IBinder sessionToken, in Surface surface, int userId); void dispatchSurfaceChanged(in IBinder sessionToken, int format, int width, int height, int userId); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl index 95b4ffa3ef5e..9e3353672af2 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl @@ -54,6 +54,7 @@ oneway interface ITvInteractiveAppSession { void notifyContentBlocked(in String rating); void notifySignalStrength(int strength); void notifyRecordingStarted(in String recordingId); + void notifyRecordingStopped(in String recordingId); void setSurface(in Surface surface); void dispatchSurfaceChanged(int format, int width, int height); void notifyBroadcastInfoResponse(in BroadcastInfoResponse response); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java index 042cb153226d..a2fdfe01ccec 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java @@ -82,6 +82,7 @@ public class ITvInteractiveAppSessionWrapper private static final int DO_RELAYOUT_MEDIA_VIEW = 28; private static final int DO_REMOVE_MEDIA_VIEW = 29; private static final int DO_NOTIFY_RECORDING_STARTED = 30; + private static final int DO_NOTIFY_RECORDING_STOPPED = 31; private final HandlerCaller mCaller; private Session mSessionImpl; @@ -169,6 +170,10 @@ public class ITvInteractiveAppSessionWrapper mSessionImpl.notifyRecordingStarted((String) msg.obj); break; } + case DO_NOTIFY_RECORDING_STOPPED: { + mSessionImpl.notifyRecordingStopped((String) msg.obj); + break; + } case DO_SEND_SIGNING_RESULT: { SomeArgs args = (SomeArgs) msg.obj; mSessionImpl.sendSigningResult((String) args.arg1, (byte[]) args.arg2); @@ -392,6 +397,12 @@ public class ITvInteractiveAppSessionWrapper } @Override + public void notifyRecordingStopped(String recordingId) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO( + DO_NOTIFY_RECORDING_STOPPED, recordingId)); + } + + @Override public void setSurface(Surface surface) { mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_SURFACE, surface)); } diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java index 0f1140706328..287df40d0d31 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java @@ -1071,6 +1071,18 @@ public final class TvInteractiveAppManager { } } + void notifyRecordingStopped(String recordingId) { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.notifyRecordingStopped(mToken, recordingId, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) { if (mToken == null) { Log.w(TAG, "The session has been already released"); diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java index 9ef65032a78d..90eed9ec83ca 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java @@ -463,6 +463,16 @@ public abstract class TvInteractiveAppService extends Service { } /** + * Receives stopped recording's ID. + * + * @param recordingId The ID of the recording stopped + * @hide + */ + public void onRecordingStopped(@NonNull String recordingId) { + } + + + /** * Receives signing result. * @param signingId the ID to identify the request. It's the same as the corresponding ID in * {@link Session#requestSigning(String, String, String, byte[])} @@ -1178,11 +1188,21 @@ public abstract class TvInteractiveAppService extends Service { onAdResponse(response); } + /** + * Calls {@link #onRecordingStarted(String)}. + */ void notifyRecordingStarted(String recordingId) { onRecordingStarted(recordingId); } /** + * Calls {@link #onRecordingStopped(String)}. + */ + void notifyRecordingStopped(String recordingId) { + onRecordingStopped(recordingId); + } + + /** * Notifies when the session state is changed. * * @param state the current session state. diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java index c21b28851afd..fcd781b85aca 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java @@ -581,9 +581,10 @@ public class TvInteractiveAppView extends ViewGroup { } /** - * Alerts the TV interactive app that a recording has been started with recordingId + * Alerts the TV interactive app that a recording has been started. * - * @param recordingId The ID of the recording started + * @param recordingId The ID of the recording started. This ID is created and maintained by the + * TV app and is used to identify the recording in the future. */ public void notifyRecordingStarted(@NonNull String recordingId) { if (DEBUG) { @@ -595,6 +596,23 @@ public class TvInteractiveAppView extends ViewGroup { } /** + * Alerts the TV interactive app that a recording has been stopped. + * + * @param recordingId The ID of the recording stopped. This ID is created and maintained + * by the TV app when a recording is started. + * @see TvInteractiveAppView#notifyRecordingStarted(String) + * @hide + */ + public void notifyRecordingStopped(@NonNull String recordingId) { + if (DEBUG) { + Log.d(TAG, "notifyRecordingStopped"); + } + if (mSession != null) { + mSession.notifyRecordingStopped(recordingId); + } + } + + /** * Sends signing result to related TV interactive app. * * <p>This is used when the corresponding server of the broadcast-independent interactive diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 51b976bf9f69..fab63aa18097 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -2376,19 +2376,20 @@ public class Tuner implements AutoCloseable { } /** - * Request a frontend by frontend id. + * Request a frontend by frontend info. * * <p> This API is used if the applications want to select a desired frontend before * {@link tune} to use a specific satellite or sending SatCR DiSEqC command for {@link tune}. * - * @param desiredId the desired fronted Id. It can be retrieved by + * @param desiredFrontendInfo the FrontendInfo of the desired fronted. It can be retrieved by * {@link getAvailableFrontendInfos} * * @return result status of open operation. * @throws SecurityException if the caller does not have appropriate permissions. */ @Result - public int requestFrontendById(int desiredId) { + public int applyFrontend(@NonNull FrontendInfo desiredFrontendInfo) { + Objects.requireNonNull(desiredFrontendInfo, "desiredFrontendInfo must not be null"); mFrontendLock.lock(); try { if (mFeOwnerTuner != null) { @@ -2399,17 +2400,12 @@ public class Tuner implements AutoCloseable { Log.e(TAG, "A frontend has been opened before"); return RESULT_INVALID_STATE; } - FrontendInfo frontendInfo = getFrontendInfoById(desiredId); - if (frontendInfo == null) { - Log.e(TAG, "Failed to get a FrontendInfo by frontend id: " + desiredId); - return RESULT_UNAVAILABLE; - } - int frontendType = frontendInfo.getType(); + mFrontendType = desiredFrontendInfo.getType(); + mDesiredFrontendId = desiredFrontendInfo.getId(); if (DEBUG) { - Log.d(TAG, "Opening frontend with type " + frontendType + ", id " + desiredId); + Log.d(TAG, "Applying frontend with type " + mFrontendType + ", id " + + mDesiredFrontendId); } - mFrontendType = frontendType; - mDesiredFrontendId = desiredId; if (!checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND, mFrontendLock)) { return RESULT_UNAVAILABLE; } diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java index 1a658320a1a9..4bcc3c6beffa 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java +++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java @@ -28,6 +28,7 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.FrameworkStatsLog; import java.util.concurrent.Executor; @@ -48,7 +49,9 @@ public class DvrRecorder implements AutoCloseable { private static int sInstantId = 0; private int mSegmentId = 0; private int mOverflow; - private Boolean mIsStopped = true; + private final Object mIsStoppedLock = new Object(); + @GuardedBy("mIsStoppedLock") + private boolean mIsStopped = true; private final Object mListenerLock = new Object(); private native int nativeAttachFilter(Filter filter); @@ -178,7 +181,7 @@ public class DvrRecorder implements AutoCloseable { .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId, FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD, FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0); - synchronized (mIsStopped) { + synchronized (mIsStoppedLock) { int result = nativeStartDvr(); if (result == Tuner.RESULT_SUCCESS) { mIsStopped = false; @@ -201,7 +204,7 @@ public class DvrRecorder implements AutoCloseable { .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId, FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD, FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mOverflow); - synchronized (mIsStopped) { + synchronized (mIsStoppedLock) { int result = nativeStopDvr(); if (result == Tuner.RESULT_SUCCESS) { mIsStopped = true; @@ -219,7 +222,7 @@ public class DvrRecorder implements AutoCloseable { */ @Result public int flush() { - synchronized (mIsStopped) { + synchronized (mIsStoppedLock) { if (mIsStopped) { return nativeFlushDvr(); } diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java index aff2e1b4cf31..89e5e0d783ff 100644 --- a/media/java/android/mtp/MtpPropertyGroup.java +++ b/media/java/android/mtp/MtpPropertyGroup.java @@ -230,7 +230,7 @@ class MtpPropertyGroup { case MtpConstants.PROPERTY_PERSISTENT_UID: // The persistent uid must be unique and never reused among all objects, // and remain the same between sessions. - long puid = (object.getPath().toString().hashCode() << 32) + long puid = (((long) object.getPath().toString().hashCode()) << 32) + object.getModifiedTime(); list.append(id, property.code, property.type, puid); break; diff --git a/media/mca/effect/java/android/media/effect/EffectFactory.java b/media/mca/effect/java/android/media/effect/EffectFactory.java index f6fcba71e339..cbb273608ad7 100644 --- a/media/mca/effect/java/android/media/effect/EffectFactory.java +++ b/media/mca/effect/java/android/media/effect/EffectFactory.java @@ -486,11 +486,9 @@ public class EffectFactory { private Effect instantiateEffect(Class effectClass, String name) { // Make sure this is an Effect subclass - try { - effectClass.asSubclass(Effect.class); - } catch (ClassCastException e) { + if (!Effect.class.isAssignableFrom(effectClass)) { throw new IllegalArgumentException("Attempting to allocate effect '" + effectClass - + "' which is not a subclass of Effect!", e); + + "' which is not a subclass of Effect!"); } // Look for the correct constructor diff --git a/media/mca/filterfw/java/android/filterfw/core/Filter.java b/media/mca/filterfw/java/android/filterfw/core/Filter.java index a608ef5be3f4..e82c046b7390 100644 --- a/media/mca/filterfw/java/android/filterfw/core/Filter.java +++ b/media/mca/filterfw/java/android/filterfw/core/Filter.java @@ -90,9 +90,7 @@ public abstract class Filter { return false; } // Then make sure it's a subclass of Filter. - try { - filterClass.asSubclass(Filter.class); - } catch (ClassCastException e) { + if (!Filter.class.isAssignableFrom(filterClass)) { return false; } return true; diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterFactory.java b/media/mca/filterfw/java/android/filterfw/core/FilterFactory.java index 779df990a9a5..736e51131ca1 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FilterFactory.java +++ b/media/mca/filterfw/java/android/filterfw/core/FilterFactory.java @@ -112,9 +112,7 @@ public class FilterFactory { public Filter createFilterByClass(Class filterClass, String filterName) { // Make sure this is a Filter subclass - try { - filterClass.asSubclass(Filter.class); - } catch (ClassCastException e) { + if (!Filter.class.isAssignableFrom(filterClass)) { throw new IllegalArgumentException("Attempting to allocate class '" + filterClass + "' which is not a subclass of Filter!"); } diff --git a/media/mca/filterfw/java/android/filterfw/core/KeyValueMap.java b/media/mca/filterfw/java/android/filterfw/core/KeyValueMap.java index 8cf9a13438e5..6ff1885fa8eb 100644 --- a/media/mca/filterfw/java/android/filterfw/core/KeyValueMap.java +++ b/media/mca/filterfw/java/android/filterfw/core/KeyValueMap.java @@ -55,12 +55,12 @@ public class KeyValueMap extends HashMap<String, Object> { public int getInt(String key) { Object result = get(key); - return result != null ? (Integer)result : null; + return result != null ? (Integer) result : 0; } public float getFloat(String key) { Object result = get(key); - return result != null ? (Float)result : null; + return result != null ? (Float) result : 0; } @Override diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java index c52816571ffb..8c05725a9ef1 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java @@ -296,7 +296,7 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med mMemWriter.write("End Memory :" + mEndMemory + "\n"); } } catch (Exception e) { - e.toString(); + // TODO } } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java index 39add7ea8a42..c814eba7d187 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java @@ -264,8 +264,14 @@ public class CameraMetadataTest extends junit.framework.TestCase { builder.append("**"); } - if (elem instanceof Number) { - builder.append(String.format("%x", elem)); + if (elem instanceof Byte) { + builder.append(String.format("%x", (Byte) elem)); + } else if (elem instanceof Short) { + builder.append(String.format("%x", (Short) elem)); + } else if (elem instanceof Integer) { + builder.append(String.format("%x", (Integer) elem)); + } else if (elem instanceof Long) { + builder.append(String.format("%x", (Long) elem)); } else { builder.append(elem); } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetCurrentPositionStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetCurrentPositionStateUnitTest.java index fd1c2d3e8e94..37dd4b5330c5 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetCurrentPositionStateUnitTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerGetCurrentPositionStateUnitTest.java @@ -18,7 +18,7 @@ package com.android.mediaframeworktest.unit; import android.media.MediaPlayer; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest;; +import android.test.suitebuilder.annotation.LargeTest; /** * Unit test class to test the set of valid and invalid states that diff --git a/packages/CarrierDefaultApp/res/values/strings.xml b/packages/CarrierDefaultApp/res/values/strings.xml index 8a19709589fd..3dcdf00ca8f5 100644 --- a/packages/CarrierDefaultApp/res/values/strings.xml +++ b/packages/CarrierDefaultApp/res/values/strings.xml @@ -15,7 +15,7 @@ <string name="ssl_error_continue">Continue anyway via browser</string> <!-- Telephony notification channel name for network boost notifications. --> - <string name="network_boost_notification_channel">Network Boost</string> + <string name="network_boost_notification_channel">Network boost</string> <!-- Notification title text for the network boost notification. --> <string name="network_boost_notification_title">%s recommends a data boost</string> <!-- Notification detail text for the network boost notification. --> diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java index dd7b218959bf..b322b8bd95bb 100644 --- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java +++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java @@ -240,11 +240,15 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{ return; } - context.getSystemService(NotificationManager.class).createNotificationChannel( - new NotificationChannel(NETWORK_BOOST_NOTIFICATION_CHANNEL_ID, - context.getResources().getString( - R.string.network_boost_notification_channel), - NotificationManager.IMPORTANCE_DEFAULT)); + NotificationChannel channel = new NotificationChannel( + NETWORK_BOOST_NOTIFICATION_CHANNEL_ID, + context.getResources().getString(R.string.network_boost_notification_channel), + NotificationManager.IMPORTANCE_DEFAULT); + // CarrierDefaultApp notifications are unblockable by default. Make this channel blockable + // to allow users to disable notifications posted to this channel without affecting other + // notifications in this application. + channel.setBlockable(true); + context.getSystemService(NotificationManager.class).createNotificationChannel(channel); Notification notification = new Notification.Builder(context, NETWORK_BOOST_NOTIFICATION_CHANNEL_ID) diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java index a7e1a5954aea..ae4046064a20 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java @@ -203,6 +203,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements initUI(); } + @SuppressWarnings("MissingSuperCall") // TODO: Fix me @Override protected void onNewIntent(Intent intent) { // Force cancels the CDM dialog if this activity receives another intent with diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/google/CloudPrintPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/google/CloudPrintPlugin.java index 93e6271319f6..3029d10d4cf3 100644 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/google/CloudPrintPlugin.java +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/google/CloudPrintPlugin.java @@ -55,18 +55,15 @@ public class CloudPrintPlugin implements PrintServicePlugin { private static final String PRIVET_SERVICE = "_privet._tcp"; /** The required mDNS service types */ - private static final Set<String> PRINTER_SERVICE_TYPE = new HashSet<String>() {{ - // Not checking _printer_._sub - add(PRIVET_SERVICE); - }}; + private static final Set<String> PRINTER_SERVICE_TYPE = Set.of( + PRIVET_SERVICE); // Not checking _printer_._sub /** All possible connection states */ - private static final Set<String> POSSIBLE_CONNECTION_STATES = new HashSet<String>() {{ - add("online"); - add("offline"); - add("connecting"); - add("not-configured"); - }}; + private static final Set<String> POSSIBLE_CONNECTION_STATES = Set.of( + "online", + "offline", + "connecting", + "not-configured"); private static final byte SUPPORTED_TXTVERS = '1'; diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java index 34e7e3d1cd6b..0c5de2741d1b 100644 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java @@ -37,9 +37,7 @@ import java.util.Set; public class MDNSFilterPlugin implements PrintServicePlugin { /** The mDNS service types supported */ - private static final Set<String> PRINTER_SERVICE_TYPES = new HashSet<String>() {{ - add("_ipp._tcp"); - }}; + private static final Set<String> PRINTER_SERVICE_TYPES = Set.of("_ipp._tcp"); /** * The printer filter for {@link MDNSFilteredDiscovery} passing only mDNS results diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterMopria.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterMopria.java index d03bb1d76003..b9983c306289 100644 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterMopria.java +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterMopria.java @@ -23,7 +23,6 @@ import android.util.Log; import com.android.printservice.recommendation.util.MDNSFilteredDiscovery; import com.android.printservice.recommendation.util.MDNSUtils; -import java.util.HashSet; import java.util.Set; /** @@ -32,10 +31,7 @@ import java.util.Set; class PrinterFilterMopria implements MDNSFilteredDiscovery.PrinterFilter { private static final String TAG = "PrinterFilterMopria"; - static final Set<String> MOPRIA_MDNS_SERVICES = new HashSet<String>() {{ - add("_ipp._tcp"); - add("_ipps._tcp"); - }}; + static final Set<String> MOPRIA_MDNS_SERVICES = Set.of("_ipp._tcp", "_ipps._tcp"); private static final String PDL__PDF = "application/pdf"; private static final String PDL__PCLM = "application/PCLm"; diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterSamsung.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterSamsung.java index b9b90988c37b..680dd84a25df 100644 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterSamsung.java +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/PrinterFilterSamsung.java @@ -25,7 +25,6 @@ import androidx.annotation.NonNull; import com.android.printservice.recommendation.util.MDNSFilteredDiscovery; import com.android.printservice.recommendation.util.MDNSUtils; -import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -36,9 +35,7 @@ import java.util.Set; class PrinterFilterSamsung implements MDNSFilteredDiscovery.PrinterFilter { private static final String TAG = "PrinterFilterSamsung"; - static final Set<String> SAMSUNG_MDNS_SERVICES = new HashSet<String>() {{ - add("_pdl-datastream._tcp"); - }}; + static final Set<String> SAMSUNG_MDNS_SERVICES = Set.of("_pdl-datastream._tcp"); private static final String[] NOT_SUPPORTED_MODELS = new String[]{ "SCX-5x15", @@ -57,9 +54,7 @@ class PrinterFilterSamsung implements MDNSFilteredDiscovery.PrinterFilter { private static final String ATTR_PRODUCT = "product"; private static final String ATTR_TY = "ty"; - private static Set<String> SAMUNG_VENDOR_SET = new HashSet<String>() {{ - add("samsung"); - }}; + private static final Set<String> SAMUNG_VENDOR_SET = Set.of("samsung"); @Override public boolean matchesCriteria(NsdServiceInfo nsdServiceInfo) { diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java index ae1bdcedaabb..cbd5833925b8 100644 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/samsung/SamsungRecommendationPlugin.java @@ -29,10 +29,11 @@ import java.util.HashSet; import java.util.Set; public class SamsungRecommendationPlugin implements PrintServicePlugin { - private static final Set<String> ALL_MDNS_SERVICES = new HashSet<String>() {{ - addAll(PrinterFilterMopria.MOPRIA_MDNS_SERVICES); - addAll(PrinterFilterSamsung.SAMSUNG_MDNS_SERVICES); - }}; + private static final Set<String> ALL_MDNS_SERVICES = new HashSet<String>(); + static { + ALL_MDNS_SERVICES.addAll(PrinterFilterMopria.MOPRIA_MDNS_SERVICES); + ALL_MDNS_SERVICES.addAll(PrinterFilterSamsung.SAMSUNG_MDNS_SERVICES); + } private final @NonNull Context mContext; private final @NonNull MDNSFilteredDiscovery mMDNSFilteredDiscovery; diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java index 00b3736f8d6b..b0aa8f19f24b 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java +++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java @@ -402,7 +402,7 @@ public final class PrintContentView extends ViewGroup implements View.OnClickLis @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { - if ((isOptionsClosed() || isOptionsClosed()) && dy <= 0) { + if (isOptionsClosed() && dy <= 0) { return; } diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt index 373b57f73ef0..a7122d0eb03a 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt @@ -54,6 +54,14 @@ interface AppListModel<T : AppRecord> { ) /** + * Gets the group title of this item. + * + * Note: Items should be sorted by group in [getComparator] first, this [getGroupTitle] will not + * change the list order. + */ + fun getGroupTitle(option: Int, record: T): String? = null + + /** * Gets the summary for the given app record. * * @return null if no summary should be displayed. diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt index 7f5fe9f75d51..681eb1c3508e 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt @@ -34,9 +34,11 @@ import com.android.settingslib.spa.framework.compose.LogCompositions import com.android.settingslib.spa.framework.compose.TimeMeasurer.Companion.rememberTimeMeasurer import com.android.settingslib.spa.framework.compose.rememberLazyListStateAndHideKeyboardWhenStartScroll import com.android.settingslib.spa.framework.compose.toState +import com.android.settingslib.spa.widget.ui.CategoryTitle import com.android.settingslib.spa.widget.ui.PlaceholderTitle import com.android.settingslib.spaprivileged.R import com.android.settingslib.spaprivileged.framework.compose.DisposableBroadcastReceiverAsUser +import com.android.settingslib.spaprivileged.model.app.AppEntry import com.android.settingslib.spaprivileged.model.app.AppListConfig import com.android.settingslib.spaprivileged.model.app.AppListData import com.android.settingslib.spaprivileged.model.app.AppListModel @@ -100,17 +102,28 @@ private fun <T : AppRecord> AppListWidget( } items(count = list.size, key = { option to list[it].record.app.packageName }) { + remember(list) { listModel.getGroupTitleIfFirst(option, list, it) } + ?.let { group -> CategoryTitle(title = group) } + val appEntry = list[it] val summary = listModel.getSummary(option, appEntry.record) ?: "".toState() - val itemModel = remember(appEntry) { + appItem(remember(appEntry) { AppListItemModel(appEntry.record, appEntry.label, summary) - } - appItem(itemModel) + }) } } } } +/** Returns group title if this is the first item of the group. */ +private fun <T : AppRecord> AppListModel<T>.getGroupTitleIfFirst( + option: Int, + list: List<AppEntry<T>>, + index: Int, +): String? = getGroupTitle(option, list[index].record)?.takeIf { + index == 0 || it != getGroupTitle(option, list[index - 1].record) +} + @Composable private fun <T : AppRecord> loadAppListData( config: AppListConfig, diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt index 80c4eac9b98f..9f20c78485a8 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt @@ -58,26 +58,43 @@ class AppListTest { @Test fun couldShowAppItem() { - setContent(appEntries = listOf(APP_ENTRY)) + setContent(appEntries = listOf(APP_ENTRY_A)) - composeTestRule.onNodeWithText(APP_ENTRY.label).assertIsDisplayed() + composeTestRule.onNodeWithText(APP_ENTRY_A.label).assertIsDisplayed() } @Test fun couldShowHeader() { - setContent(header = { Text(HEADER) }, appEntries = listOf(APP_ENTRY)) + setContent(appEntries = listOf(APP_ENTRY_A), header = { Text(HEADER) }) composeTestRule.onNodeWithText(HEADER).assertIsDisplayed() } + @Test + fun whenNotGrouped_groupTitleDoesNotExist() { + setContent(appEntries = listOf(APP_ENTRY_A, APP_ENTRY_B), enableGrouping = false) + + composeTestRule.onNodeWithText(GROUP_A).assertDoesNotExist() + composeTestRule.onNodeWithText(GROUP_B).assertDoesNotExist() + } + + @Test + fun whenGrouped_groupTitleDisplayed() { + setContent(appEntries = listOf(APP_ENTRY_A, APP_ENTRY_B), enableGrouping = true) + + composeTestRule.onNodeWithText(GROUP_A).assertIsDisplayed() + composeTestRule.onNodeWithText(GROUP_B).assertIsDisplayed() + } + private fun setContent( - header: @Composable () -> Unit = {}, appEntries: List<AppEntry<TestAppRecord>>, + header: @Composable () -> Unit = {}, + enableGrouping: Boolean = false, ) { composeTestRule.setContent { AppList( config = AppListConfig(userId = USER_ID, showInstantApps = false), - listModel = TestAppListModel(), + listModel = TestAppListModel(enableGrouping), state = AppListState( showSystem = false.toState(), option = 0.toState(), @@ -96,17 +113,37 @@ class AppListTest { private companion object { const val USER_ID = 0 const val HEADER = "Header" - val APP_ENTRY = AppEntry( - record = TestAppRecord(ApplicationInfo()), - label = "AAA", + const val GROUP_A = "Group A" + const val GROUP_B = "Group B" + val APP_ENTRY_A = AppEntry( + record = TestAppRecord( + app = ApplicationInfo().apply { + packageName = "package.name.a" + }, + group = GROUP_A, + ), + label = "Label A", + labelCollationKey = CollationKey("", byteArrayOf()), + ) + val APP_ENTRY_B = AppEntry( + record = TestAppRecord( + app = ApplicationInfo().apply { + packageName = "package.name.b" + }, + group = GROUP_B, + ), + label = "Label B", labelCollationKey = CollationKey("", byteArrayOf()), ) } } -private data class TestAppRecord(override val app: ApplicationInfo) : AppRecord +private data class TestAppRecord( + override val app: ApplicationInfo, + val group: String? = null, +) : AppRecord -private class TestAppListModel : AppListModel<TestAppRecord> { +private class TestAppListModel(val enableGrouping: Boolean) : AppListModel<TestAppRecord> { override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) = appListFlow.asyncMapItem { TestAppRecord(it) } @@ -118,4 +155,7 @@ private class TestAppListModel : AppListModel<TestAppRecord> { option: Int, recordListFlow: Flow<List<TestAppRecord>>, ) = recordListFlow + + override fun getGroupTitle(option: Int, record: TestAppRecord) = + if (enableGrouping) record.group else null } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java index 6ce72bbc6909..3af64e2889e7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java @@ -82,4 +82,4 @@ public class BluetoothDiscoverableTimeoutReceiver extends BroadcastReceiver { Log.e(TAG, "localBluetoothAdapter is NULL!!"); } } -}; +} diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 90fab08ed43e..2e4a245df6a6 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -720,6 +720,57 @@ <!-- Permission required for CTS test - CtsDeviceLockTestCases --> <uses-permission android:name="android.permission.MANAGE_DEVICE_LOCK_STATE" /> + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" /> + + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" /> + + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> + + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" /> + + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" /> + + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" /> + + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" /> + + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" /> + + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH" /> + + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING" /> + + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" /> + + <!-- Permission required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" /> + + <!-- Permissions required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.CAPTURE_MEDIA_OUTPUT" /> + + <!-- Permissions required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.CAPTURE_TUNER_AUDIO_INPUT" /> + + <!-- Permissions required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT" /> + + <!-- Permissions required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> + + <!-- Permissions required for CTS test - CtsAppFgsTestCases --> + <uses-permission android:name="android.permission.USE_EXACT_ALARM" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 55d637916d0c..f4d802bf745e 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -743,12 +743,35 @@ <!-- How long in milliseconds before full burn-in protection is achieved. --> <integer name="config_dreamOverlayMillisUntilFullJitter">240000</integer> + <!-- The duration in milliseconds of the y-translation animation when waking up from + the dream --> + <integer name="config_dreamOverlayOutTranslationYDurationMs">333</integer> + <!-- The delay in milliseconds of the y-translation animation when waking up from + the dream for the complications at the bottom of the screen --> + <integer name="config_dreamOverlayOutTranslationYDelayBottomMs">33</integer> + <!-- The delay in milliseconds of the y-translation animation when waking up from + the dream for the complications at the top of the screen --> + <integer name="config_dreamOverlayOutTranslationYDelayTopMs">117</integer> + <!-- The duration in milliseconds of the alpha animation when waking up from the dream --> + <integer name="config_dreamOverlayOutAlphaDurationMs">200</integer> + <!-- The delay in milliseconds of the alpha animation when waking up from the dream for the + complications at the top of the screen --> + <integer name="config_dreamOverlayOutAlphaDelayTopMs">217</integer> + <!-- The delay in milliseconds of the alpha animation when waking up from the dream for the + complications at the bottom of the screen --> + <integer name="config_dreamOverlayOutAlphaDelayBottomMs">133</integer> + <!-- The duration in milliseconds of the blur animation when waking up from + the dream --> + <integer name="config_dreamOverlayOutBlurDurationMs">250</integer> + <integer name="complicationFadeOutMs">500</integer> <integer name="complicationFadeInMs">500</integer> <integer name="complicationRestoreMs">1000</integer> + <integer name="complicationFadeOutDelayMs">200</integer> + <!-- Duration in milliseconds of the dream in un-blur animation. --> <integer name="config_dreamOverlayInBlurDurationMs">249</integer> <!-- Delay in milliseconds of the dream in un-blur animation. --> @@ -780,27 +803,6 @@ <item>com.android.systemui</item> </string-array> - <!-- The thresholds which determine the color used by the AQI dream overlay. - NOTE: This must always be kept sorted from low to high --> - <integer-array name="config_dreamAqiThresholds"> - <item>-1</item> - <item>50</item> - <item>100</item> - <item>150</item> - <item>200</item> - <item>300</item> - </integer-array> - - <!-- The color values which correspond to the thresholds above --> - <integer-array name="config_dreamAqiColorValues"> - <item>@color/dream_overlay_aqi_good</item> - <item>@color/dream_overlay_aqi_moderate</item> - <item>@color/dream_overlay_aqi_unhealthy_sensitive</item> - <item>@color/dream_overlay_aqi_unhealthy</item> - <item>@color/dream_overlay_aqi_very_unhealthy</item> - <item>@color/dream_overlay_aqi_hazardous</item> - </integer-array> - <!-- Whether the device should display hotspot UI. If true, UI will display only when tethering is available. If false, UI will never show regardless of tethering availability" --> <bool name="config_show_wifi_tethering">true</bool> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 6577b07f7139..fbdccff38731 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1552,6 +1552,7 @@ <dimen name="dream_overlay_complication_margin">0dp</dimen> <dimen name="dream_overlay_y_offset">80dp</dimen> + <dimen name="dream_overlay_exit_y_offset">40dp</dimen> <dimen name="dream_aqi_badge_corner_radius">28dp</dimen> <dimen name="dream_aqi_badge_padding_vertical">6dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 80dff856cfb2..eb291fd5f12a 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -405,8 +405,8 @@ <string name="keyguard_face_failed">Can\u2019t recognize face</string> <!-- Message shown to suggest using fingerprint sensor to authenticate after another biometric failed. [CHAR LIMIT=25] --> <string name="keyguard_suggest_fingerprint">Use fingerprint instead</string> - <!-- Message shown to inform the user that face unlock is not available. [CHAR LIMIT=65] --> - <string name="keyguard_face_unlock_unavailable">Face unlock unavailable.</string> + <!-- Message shown to inform the user that face unlock is not available. [CHAR LIMIT=59] --> + <string name="keyguard_face_unlock_unavailable">Face Unlock unavailable</string> <!-- Content description of the bluetooth icon when connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_bluetooth_connected">Bluetooth connected.</string> diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java index 0a2dc5b182d8..d60cc7579ea8 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java @@ -291,8 +291,11 @@ public class SystemActions implements CoreStartable { mA11yManager.registerSystemAction(actionBack, SYSTEM_ACTION_ID_BACK); mA11yManager.registerSystemAction(actionHome, SYSTEM_ACTION_ID_HOME); mA11yManager.registerSystemAction(actionRecents, SYSTEM_ACTION_ID_RECENTS); - mA11yManager.registerSystemAction(actionNotifications, SYSTEM_ACTION_ID_NOTIFICATIONS); - mA11yManager.registerSystemAction(actionQuickSettings, SYSTEM_ACTION_ID_QUICK_SETTINGS); + if (mCentralSurfacesOptionalLazy.get().isPresent()) { + // These two actions require the CentralSurfaces instance. + mA11yManager.registerSystemAction(actionNotifications, SYSTEM_ACTION_ID_NOTIFICATIONS); + mA11yManager.registerSystemAction(actionQuickSettings, SYSTEM_ACTION_ID_QUICK_SETTINGS); + } mA11yManager.registerSystemAction(actionPowerDialog, SYSTEM_ACTION_ID_POWER_DIALOG); mA11yManager.registerSystemAction(actionLockScreen, SYSTEM_ACTION_ID_LOCK_SCREEN); mA11yManager.registerSystemAction(actionTakeScreenshot, SYSTEM_ACTION_ID_TAKE_SCREENSHOT); diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt index d8dd6a21d4c1..0087c8439370 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt @@ -17,17 +17,19 @@ package com.android.systemui.dreams import android.animation.Animator -import android.animation.AnimatorListenerAdapter import android.animation.AnimatorSet import android.animation.ValueAnimator import android.view.View +import android.view.animation.Interpolator +import androidx.annotation.FloatRange import androidx.core.animation.doOnEnd import com.android.systemui.animation.Interpolators import com.android.systemui.dreams.complication.ComplicationHostViewController import com.android.systemui.dreams.complication.ComplicationLayoutParams +import com.android.systemui.dreams.complication.ComplicationLayoutParams.Position import com.android.systemui.dreams.dagger.DreamOverlayModule import com.android.systemui.statusbar.BlurUtils -import java.util.function.Consumer +import com.android.systemui.statusbar.CrossFadeHelper import javax.inject.Inject import javax.inject.Named @@ -40,108 +42,239 @@ constructor( private val mStatusBarViewController: DreamOverlayStatusBarViewController, private val mOverlayStateController: DreamOverlayStateController, @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DURATION) - private val mDreamInBlurAnimDuration: Int, - @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DELAY) private val mDreamInBlurAnimDelay: Int, + private val mDreamInBlurAnimDurationMs: Long, + @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DELAY) + private val mDreamInBlurAnimDelayMs: Long, @Named(DreamOverlayModule.DREAM_IN_COMPLICATIONS_ANIMATION_DURATION) - private val mDreamInComplicationsAnimDuration: Int, + private val mDreamInComplicationsAnimDurationMs: Long, @Named(DreamOverlayModule.DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY) - private val mDreamInTopComplicationsAnimDelay: Int, + private val mDreamInTopComplicationsAnimDelayMs: Long, @Named(DreamOverlayModule.DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY) - private val mDreamInBottomComplicationsAnimDelay: Int + private val mDreamInBottomComplicationsAnimDelayMs: Long, + @Named(DreamOverlayModule.DREAM_OUT_TRANSLATION_Y_DISTANCE) + private val mDreamOutTranslationYDistance: Int, + @Named(DreamOverlayModule.DREAM_OUT_TRANSLATION_Y_DURATION) + private val mDreamOutTranslationYDurationMs: Long, + @Named(DreamOverlayModule.DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM) + private val mDreamOutTranslationYDelayBottomMs: Long, + @Named(DreamOverlayModule.DREAM_OUT_TRANSLATION_Y_DELAY_TOP) + private val mDreamOutTranslationYDelayTopMs: Long, + @Named(DreamOverlayModule.DREAM_OUT_ALPHA_DURATION) private val mDreamOutAlphaDurationMs: Long, + @Named(DreamOverlayModule.DREAM_OUT_ALPHA_DELAY_BOTTOM) + private val mDreamOutAlphaDelayBottomMs: Long, + @Named(DreamOverlayModule.DREAM_OUT_ALPHA_DELAY_TOP) private val mDreamOutAlphaDelayTopMs: Long, + @Named(DreamOverlayModule.DREAM_OUT_BLUR_DURATION) private val mDreamOutBlurDurationMs: Long ) { - var mEntryAnimations: AnimatorSet? = null + private var mAnimator: Animator? = null + + /** + * Store the current alphas at the various positions. This is so that we may resume an animation + * at the current alpha. + */ + private var mCurrentAlphaAtPosition = mutableMapOf<Int, Float>() + + @FloatRange(from = 0.0, to = 1.0) private var mBlurProgress: Float = 0f /** Starts the dream content and dream overlay entry animations. */ - fun startEntryAnimations(view: View) { - cancelRunningEntryAnimations() - - mEntryAnimations = AnimatorSet() - mEntryAnimations?.apply { - playTogether( - buildDreamInBlurAnimator(view), - buildDreamInTopComplicationsAnimator(), - buildDreamInBottomComplicationsAnimator() - ) - doOnEnd { mOverlayStateController.setEntryAnimationsFinished(true) } - start() - } + @JvmOverloads + fun startEntryAnimations(view: View, animatorBuilder: () -> AnimatorSet = { AnimatorSet() }) { + cancelAnimations() + + mAnimator = + animatorBuilder().apply { + playTogether( + blurAnimator( + view = view, + from = 1f, + to = 0f, + durationMs = mDreamInBlurAnimDurationMs, + delayMs = mDreamInBlurAnimDelayMs + ), + alphaAnimator( + from = 0f, + to = 1f, + durationMs = mDreamInComplicationsAnimDurationMs, + delayMs = mDreamInTopComplicationsAnimDelayMs, + position = ComplicationLayoutParams.POSITION_TOP + ), + alphaAnimator( + from = 0f, + to = 1f, + durationMs = mDreamInComplicationsAnimDurationMs, + delayMs = mDreamInBottomComplicationsAnimDelayMs, + position = ComplicationLayoutParams.POSITION_BOTTOM + ) + ) + doOnEnd { + mAnimator = null + mOverlayStateController.setEntryAnimationsFinished(true) + } + start() + } + } + + /** Starts the dream content and dream overlay exit animations. */ + @JvmOverloads + fun startExitAnimations( + view: View, + doneCallback: () -> Unit, + animatorBuilder: () -> AnimatorSet = { AnimatorSet() } + ) { + cancelAnimations() + + mAnimator = + animatorBuilder().apply { + playTogether( + blurAnimator( + view = view, + // Start the blurring wherever the entry animation ended, in + // case it was cancelled early. + from = mBlurProgress, + to = 1f, + durationMs = mDreamOutBlurDurationMs + ), + translationYAnimator( + from = 0f, + to = mDreamOutTranslationYDistance.toFloat(), + durationMs = mDreamOutTranslationYDurationMs, + delayMs = mDreamOutTranslationYDelayBottomMs, + position = ComplicationLayoutParams.POSITION_BOTTOM, + animInterpolator = Interpolators.EMPHASIZED_ACCELERATE + ), + translationYAnimator( + from = 0f, + to = mDreamOutTranslationYDistance.toFloat(), + durationMs = mDreamOutTranslationYDurationMs, + delayMs = mDreamOutTranslationYDelayTopMs, + position = ComplicationLayoutParams.POSITION_TOP, + animInterpolator = Interpolators.EMPHASIZED_ACCELERATE + ), + alphaAnimator( + from = + mCurrentAlphaAtPosition.getOrDefault( + key = ComplicationLayoutParams.POSITION_BOTTOM, + defaultValue = 1f + ), + to = 0f, + durationMs = mDreamOutAlphaDurationMs, + delayMs = mDreamOutAlphaDelayBottomMs, + position = ComplicationLayoutParams.POSITION_BOTTOM + ), + alphaAnimator( + from = + mCurrentAlphaAtPosition.getOrDefault( + key = ComplicationLayoutParams.POSITION_TOP, + defaultValue = 1f + ), + to = 0f, + durationMs = mDreamOutAlphaDurationMs, + delayMs = mDreamOutAlphaDelayTopMs, + position = ComplicationLayoutParams.POSITION_TOP + ) + ) + doOnEnd { + mAnimator = null + mOverlayStateController.setExitAnimationsRunning(false) + doneCallback() + } + start() + } + mOverlayStateController.setExitAnimationsRunning(true) } /** Cancels the dream content and dream overlay animations, if they're currently running. */ - fun cancelRunningEntryAnimations() { - if (mEntryAnimations?.isRunning == true) { - mEntryAnimations?.cancel() - } - mEntryAnimations = null + fun cancelAnimations() { + mAnimator = + mAnimator?.let { + it.cancel() + null + } } - private fun buildDreamInBlurAnimator(view: View): Animator { - return ValueAnimator.ofFloat(1f, 0f).apply { - duration = mDreamInBlurAnimDuration.toLong() - startDelay = mDreamInBlurAnimDelay.toLong() + private fun blurAnimator( + view: View, + from: Float, + to: Float, + durationMs: Long, + delayMs: Long = 0 + ): Animator { + return ValueAnimator.ofFloat(from, to).apply { + duration = durationMs + startDelay = delayMs interpolator = Interpolators.LINEAR addUpdateListener { animator: ValueAnimator -> + mBlurProgress = animator.animatedValue as Float mBlurUtils.applyBlur( - view.viewRootImpl, - mBlurUtils.blurRadiusOfRatio(animator.animatedValue as Float).toInt(), - false /*opaque*/ + viewRootImpl = view.viewRootImpl, + radius = mBlurUtils.blurRadiusOfRatio(mBlurProgress).toInt(), + opaque = false ) } } } - private fun buildDreamInTopComplicationsAnimator(): Animator { - return ValueAnimator.ofFloat(0f, 1f).apply { - duration = mDreamInComplicationsAnimDuration.toLong() - startDelay = mDreamInTopComplicationsAnimDelay.toLong() + private fun alphaAnimator( + from: Float, + to: Float, + durationMs: Long, + delayMs: Long, + @Position position: Int + ): Animator { + return ValueAnimator.ofFloat(from, to).apply { + duration = durationMs + startDelay = delayMs interpolator = Interpolators.LINEAR addUpdateListener { va: ValueAnimator -> - setTopElementsAlpha(va.animatedValue as Float) + setElementsAlphaAtPosition( + alpha = va.animatedValue as Float, + position = position, + fadingOut = to < from + ) } } } - private fun buildDreamInBottomComplicationsAnimator(): Animator { - return ValueAnimator.ofFloat(0f, 1f).apply { - duration = mDreamInComplicationsAnimDuration.toLong() - startDelay = mDreamInBottomComplicationsAnimDelay.toLong() - interpolator = Interpolators.LINEAR + private fun translationYAnimator( + from: Float, + to: Float, + durationMs: Long, + delayMs: Long, + @Position position: Int, + animInterpolator: Interpolator + ): Animator { + return ValueAnimator.ofFloat(from, to).apply { + duration = durationMs + startDelay = delayMs + interpolator = animInterpolator addUpdateListener { va: ValueAnimator -> - setBottomElementsAlpha(va.animatedValue as Float) + setElementsTranslationYAtPosition(va.animatedValue as Float, position) } - addListener( - object : AnimatorListenerAdapter() { - override fun onAnimationStart(animation: Animator) { - mComplicationHostViewController - .getViewsAtPosition(ComplicationLayoutParams.POSITION_BOTTOM) - .forEach(Consumer { v: View -> v.visibility = View.VISIBLE }) - } - } - ) } } - /** Sets alpha of top complications and the status bar. */ - private fun setTopElementsAlpha(alpha: Float) { - mComplicationHostViewController - .getViewsAtPosition(ComplicationLayoutParams.POSITION_TOP) - .forEach(Consumer { v: View -> setAlphaAndEnsureVisible(v, alpha) }) - mStatusBarViewController.setAlpha(alpha) - } - - /** Sets alpha of bottom complications. */ - private fun setBottomElementsAlpha(alpha: Float) { - mComplicationHostViewController - .getViewsAtPosition(ComplicationLayoutParams.POSITION_BOTTOM) - .forEach(Consumer { v: View -> setAlphaAndEnsureVisible(v, alpha) }) + /** Sets alpha of complications at the specified position. */ + private fun setElementsAlphaAtPosition(alpha: Float, position: Int, fadingOut: Boolean) { + mCurrentAlphaAtPosition[position] = alpha + mComplicationHostViewController.getViewsAtPosition(position).forEach { view -> + if (fadingOut) { + CrossFadeHelper.fadeOut(view, 1 - alpha, /* remap= */ false) + } else { + CrossFadeHelper.fadeIn(view, alpha, /* remap= */ false) + } + } + if (position == ComplicationLayoutParams.POSITION_TOP) { + mStatusBarViewController.setFadeAmount(alpha, fadingOut) + } } - private fun setAlphaAndEnsureVisible(view: View, alpha: Float) { - if (alpha > 0 && view.visibility != View.VISIBLE) { - view.visibility = View.VISIBLE + /** Sets y translation of complications at the specified position. */ + private fun setElementsTranslationYAtPosition(translationY: Float, position: Int) { + mComplicationHostViewController.getViewsAtPosition(position).forEach { v -> + v.translationY = translationY + } + if (position == ComplicationLayoutParams.POSITION_TOP) { + mStatusBarViewController.setTranslationY(translationY) } - - view.alpha = alpha } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java index 5c6d24813570..9d7ad305c7e5 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java @@ -29,6 +29,8 @@ import android.util.MathUtils; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; + import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.dagger.qualifiers.Main; @@ -42,6 +44,7 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.util.ViewController; import java.util.Arrays; +import java.util.concurrent.Executor; import javax.inject.Inject; import javax.inject.Named; @@ -194,7 +197,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve } mPrimaryBouncerCallbackInteractor.removeBouncerExpansionCallback(mBouncerExpansionCallback); - mDreamOverlayAnimationsController.cancelRunningEntryAnimations(); + mDreamOverlayAnimationsController.cancelAnimations(); } View getContainerView() { @@ -251,4 +254,17 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve : aboutToShowBouncerProgress(expansion + 0.03f)); return MathUtils.lerp(-mDreamOverlayMaxTranslationY, 0, fraction); } + + /** + * Handle the dream waking up and run any necessary animations. + * + * @param onAnimationEnd Callback to trigger once animations are finished. + * @param callbackExecutor Executor to execute the callback on. + */ + public void wakeUp(@NonNull Runnable onAnimationEnd, @NonNull Executor callbackExecutor) { + mDreamOverlayAnimationsController.startExitAnimations(mView, () -> { + callbackExecutor.execute(onAnimationEnd); + return null; + }); + } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index 8542412f82f8..e76d5b30d3e6 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -213,6 +213,15 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ mLifecycleRegistry.setCurrentState(state); } + @Override + public void onWakeUp(@NonNull Runnable onCompletedCallback) { + mExecutor.execute(() -> { + if (mDreamOverlayContainerViewController != null) { + mDreamOverlayContainerViewController.wakeUp(onCompletedCallback, mExecutor); + } + }); + } + /** * Inserts {@link Window} to host the dream overlay into the dream's parent window. Must be * called from the main executing thread. The window attributes closely mirror those that are diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java index e80d0beabf2b..5f942b6fb834 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java @@ -52,6 +52,7 @@ public class DreamOverlayStateController implements public static final int STATE_DREAM_OVERLAY_ACTIVE = 1 << 0; public static final int STATE_LOW_LIGHT_ACTIVE = 1 << 1; public static final int STATE_DREAM_ENTRY_ANIMATIONS_FINISHED = 1 << 2; + public static final int STATE_DREAM_EXIT_ANIMATIONS_RUNNING = 1 << 3; private static final int OP_CLEAR_STATE = 1; private static final int OP_SET_STATE = 2; @@ -211,6 +212,14 @@ public class DreamOverlayStateController implements return containsState(STATE_DREAM_ENTRY_ANIMATIONS_FINISHED); } + /** + * Returns whether the dream content and dream overlay exit animations are running. + * @return {@code true} if animations are running, {@code false} otherwise. + */ + public boolean areExitAnimationsRunning() { + return containsState(STATE_DREAM_EXIT_ANIMATIONS_RUNNING); + } + private boolean containsState(int state) { return (mState & state) != 0; } @@ -257,6 +266,15 @@ public class DreamOverlayStateController implements } /** + * Sets whether dream content and dream overlay exit animations are running. + * @param running {@code true} if exit animations are running, {@code false} otherwise. + */ + public void setExitAnimationsRunning(boolean running) { + modifyState(running ? OP_SET_STATE : OP_CLEAR_STATE, + STATE_DREAM_EXIT_ANIMATIONS_RUNNING); + } + + /** * Returns the available complication types. */ @Complication.ComplicationType diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java index d17fbe31c8d2..f1bb156199ef 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java @@ -37,6 +37,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider.StatusBarItem; import com.android.systemui.dreams.dagger.DreamOverlayComponent; +import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.ZenModeController; @@ -217,18 +218,29 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve } /** - * Sets alpha of the dream overlay status bar. + * Sets fade of the dream overlay status bar. * * No-op if the dream overlay status bar should not be shown. */ - protected void setAlpha(float alpha) { + protected void setFadeAmount(float fadeAmount, boolean fadingOut) { updateVisibility(); if (mView.getVisibility() != View.VISIBLE) { return; } - mView.setAlpha(alpha); + if (fadingOut) { + CrossFadeHelper.fadeOut(mView, 1 - fadeAmount, /* remap= */ false); + } else { + CrossFadeHelper.fadeIn(mView, fadeAmount, /* remap= */ false); + } + } + + /** + * Sets the y translation of the dream overlay status bar. + */ + public void setTranslationY(float translationY) { + mView.setTranslationY(translationY); } private boolean shouldShowStatusBar() { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java index 41f557850f88..b07efdfff5f2 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java @@ -197,11 +197,11 @@ public interface Complication { */ interface VisibilityController { /** - * Called to set the visibility of all shown and future complications. + * Called to set the visibility of all shown and future complications. Changes in visibility + * will always be animated. * @param visibility The desired future visibility. - * @param animate whether the change should be animated. */ - void setVisibility(@View.Visibility int visibility, boolean animate); + void setVisibility(@View.Visibility int visibility); } /** diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java index 440dcbc18a12..48159aed524e 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java @@ -21,12 +21,9 @@ import static com.android.systemui.dreams.complication.dagger.ComplicationHostVi import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN_DEFAULT; import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.SCOPED_COMPLICATIONS_LAYOUT; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.util.Log; import android.view.View; import android.view.ViewGroup; -import android.view.ViewPropertyAnimator; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.Constraints; @@ -34,6 +31,7 @@ import androidx.constraintlayout.widget.Constraints; import com.android.systemui.R; import com.android.systemui.dreams.complication.ComplicationLayoutParams.Position; import com.android.systemui.dreams.dagger.DreamOverlayComponent; +import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.touch.TouchInsetManager; import java.util.ArrayList; @@ -481,7 +479,6 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll private final TouchInsetManager.TouchInsetSession mSession; private final int mFadeInDuration; private final int mFadeOutDuration; - private ViewPropertyAnimator mViewPropertyAnimator; /** */ @Inject @@ -498,26 +495,16 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll } @Override - public void setVisibility(int visibility, boolean animate) { - final boolean appearing = visibility == View.VISIBLE; - - if (mViewPropertyAnimator != null) { - mViewPropertyAnimator.cancel(); - } - - if (appearing) { - mLayout.setVisibility(View.VISIBLE); + public void setVisibility(int visibility) { + if (visibility == View.VISIBLE) { + CrossFadeHelper.fadeIn(mLayout, mFadeInDuration, /* delay= */ 0); + } else { + CrossFadeHelper.fadeOut( + mLayout, + mFadeOutDuration, + /* delay= */ 0, + /* endRunnable= */ null); } - - mViewPropertyAnimator = mLayout.animate() - .alpha(appearing ? 1f : 0f) - .setDuration(appearing ? mFadeInDuration : mFadeOutDuration) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mLayout.setVisibility(visibility); - } - }); } /** diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java index 2b32d349dd67..4fae68d57ee8 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java @@ -38,7 +38,7 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { POSITION_START, }) - @interface Position {} + public @interface Position {} /** Align view with the top of parent or bottom of preceding {@link Complication}. */ public static final int POSITION_TOP = 1 << 0; /** Align view with the bottom of parent or top of preceding {@link Complication}. */ diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java index c9fecc96c1b5..09cc7c51ccf4 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java @@ -41,6 +41,7 @@ public abstract class ComplicationHostViewModule { public static final String COMPLICATIONS_FADE_OUT_DURATION = "complications_fade_out_duration"; public static final String COMPLICATIONS_FADE_IN_DURATION = "complications_fade_in_duration"; public static final String COMPLICATIONS_RESTORE_TIMEOUT = "complication_restore_timeout"; + public static final String COMPLICATIONS_FADE_OUT_DELAY = "complication_fade_out_delay"; /** * Generates a {@link ConstraintLayout}, which can host @@ -75,6 +76,16 @@ public abstract class ComplicationHostViewModule { } /** + * Provides the delay to wait for before fading out complications. + */ + @Provides + @Named(COMPLICATIONS_FADE_OUT_DELAY) + @DreamOverlayComponent.DreamOverlayScope + static int providesComplicationsFadeOutDelay(@Main Resources resources) { + return resources.getInteger(R.integer.complicationFadeOutDelayMs); + } + + /** * Provides the fade in duration for complications. */ @Provides diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java index cb012fa42e94..ed0e1d97e40a 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java @@ -55,6 +55,22 @@ public abstract class DreamOverlayModule { "dream_in_top_complications_anim_delay"; public static final String DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY = "dream_in_bottom_complications_anim_delay"; + public static final String DREAM_OUT_TRANSLATION_Y_DISTANCE = + "dream_out_complications_translation_y"; + public static final String DREAM_OUT_TRANSLATION_Y_DURATION = + "dream_out_complications_translation_y_duration"; + public static final String DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM = + "dream_out_complications_translation_y_delay_bottom"; + public static final String DREAM_OUT_TRANSLATION_Y_DELAY_TOP = + "dream_out_complications_translation_y_delay_top"; + public static final String DREAM_OUT_ALPHA_DURATION = + "dream_out_complications_alpha_duration"; + public static final String DREAM_OUT_ALPHA_DELAY_BOTTOM = + "dream_out_complications_alpha_delay_bottom"; + public static final String DREAM_OUT_ALPHA_DELAY_TOP = + "dream_out_complications_alpha_delay_top"; + public static final String DREAM_OUT_BLUR_DURATION = + "dream_out_blur_duration"; /** */ @Provides @@ -127,8 +143,8 @@ public abstract class DreamOverlayModule { */ @Provides @Named(DREAM_IN_BLUR_ANIMATION_DURATION) - static int providesDreamInBlurAnimationDuration(@Main Resources resources) { - return resources.getInteger(R.integer.config_dreamOverlayInBlurDurationMs); + static long providesDreamInBlurAnimationDuration(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayInBlurDurationMs); } /** @@ -136,8 +152,8 @@ public abstract class DreamOverlayModule { */ @Provides @Named(DREAM_IN_BLUR_ANIMATION_DELAY) - static int providesDreamInBlurAnimationDelay(@Main Resources resources) { - return resources.getInteger(R.integer.config_dreamOverlayInBlurDelayMs); + static long providesDreamInBlurAnimationDelay(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayInBlurDelayMs); } /** @@ -145,8 +161,8 @@ public abstract class DreamOverlayModule { */ @Provides @Named(DREAM_IN_COMPLICATIONS_ANIMATION_DURATION) - static int providesDreamInComplicationsAnimationDuration(@Main Resources resources) { - return resources.getInteger(R.integer.config_dreamOverlayInComplicationsDurationMs); + static long providesDreamInComplicationsAnimationDuration(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayInComplicationsDurationMs); } /** @@ -154,8 +170,8 @@ public abstract class DreamOverlayModule { */ @Provides @Named(DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY) - static int providesDreamInTopComplicationsAnimationDelay(@Main Resources resources) { - return resources.getInteger(R.integer.config_dreamOverlayInTopComplicationsDelayMs); + static long providesDreamInTopComplicationsAnimationDelay(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayInTopComplicationsDelayMs); } /** @@ -163,8 +179,69 @@ public abstract class DreamOverlayModule { */ @Provides @Named(DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY) - static int providesDreamInBottomComplicationsAnimationDelay(@Main Resources resources) { - return resources.getInteger(R.integer.config_dreamOverlayInBottomComplicationsDelayMs); + static long providesDreamInBottomComplicationsAnimationDelay(@Main Resources resources) { + return (long) resources.getInteger( + R.integer.config_dreamOverlayInBottomComplicationsDelayMs); + } + + /** + * Provides the number of pixels to translate complications when waking up from dream. + */ + @Provides + @Named(DREAM_OUT_TRANSLATION_Y_DISTANCE) + @DreamOverlayComponent.DreamOverlayScope + static int providesDreamOutComplicationsTranslationY(@Main Resources resources) { + return resources.getDimensionPixelSize(R.dimen.dream_overlay_exit_y_offset); + } + + @Provides + @Named(DREAM_OUT_TRANSLATION_Y_DURATION) + @DreamOverlayComponent.DreamOverlayScope + static long providesDreamOutComplicationsTranslationYDuration(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayOutTranslationYDurationMs); + } + + @Provides + @Named(DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM) + @DreamOverlayComponent.DreamOverlayScope + static long providesDreamOutComplicationsTranslationYDelayBottom(@Main Resources resources) { + return (long) resources.getInteger( + R.integer.config_dreamOverlayOutTranslationYDelayBottomMs); + } + + @Provides + @Named(DREAM_OUT_TRANSLATION_Y_DELAY_TOP) + @DreamOverlayComponent.DreamOverlayScope + static long providesDreamOutComplicationsTranslationYDelayTop(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayOutTranslationYDelayTopMs); + } + + @Provides + @Named(DREAM_OUT_ALPHA_DURATION) + @DreamOverlayComponent.DreamOverlayScope + static long providesDreamOutComplicationsAlphaDuration(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayOutAlphaDurationMs); + } + + @Provides + @Named(DREAM_OUT_ALPHA_DELAY_BOTTOM) + @DreamOverlayComponent.DreamOverlayScope + static long providesDreamOutComplicationsAlphaDelayBottom(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayOutAlphaDelayBottomMs); + } + + @Provides + @Named(DREAM_OUT_ALPHA_DELAY_TOP) + @DreamOverlayComponent.DreamOverlayScope + static long providesDreamOutComplicationsAlphaDelayTop(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayOutAlphaDelayTopMs); + } + + @Provides + @Named(DREAM_OUT_BLUR_DURATION) + @DreamOverlayComponent.DreamOverlayScope + static long providesDreamOutBlurDuration(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayOutBlurDurationMs); } @Provides diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java index 3087cdfd0cc0..e276e0c65b1e 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java @@ -16,22 +16,26 @@ package com.android.systemui.dreams.touch; +import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_OUT_DELAY; import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_RESTORE_TIMEOUT; -import android.os.Handler; import android.util.Log; import android.view.MotionEvent; import android.view.View; +import androidx.annotation.Nullable; + import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.complication.Complication; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.touch.TouchInsetManager; +import com.android.systemui.util.concurrency.DelayableExecutor; import com.google.common.util.concurrent.ListenableFuture; +import java.util.ArrayDeque; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; import javax.inject.Inject; import javax.inject.Named; @@ -49,33 +53,58 @@ public class HideComplicationTouchHandler implements DreamTouchHandler { private static final String TAG = "HideComplicationHandler"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private final Complication.VisibilityController mVisibilityController; private final int mRestoreTimeout; + private final int mFadeOutDelay; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; - private final Handler mHandler; - private final Executor mExecutor; + private final DelayableExecutor mExecutor; + private final DreamOverlayStateController mOverlayStateController; private final TouchInsetManager mTouchInsetManager; + private final Complication.VisibilityController mVisibilityController; + private boolean mHidden = false; + @Nullable + private Runnable mHiddenCallback; + private final ArrayDeque<Runnable> mCancelCallbacks = new ArrayDeque<>(); + private final Runnable mRestoreComplications = new Runnable() { @Override public void run() { - mVisibilityController.setVisibility(View.VISIBLE, true); + mVisibilityController.setVisibility(View.VISIBLE); + mHidden = false; + } + }; + + private final Runnable mHideComplications = new Runnable() { + @Override + public void run() { + if (mOverlayStateController.areExitAnimationsRunning()) { + // Avoid interfering with the exit animations. + return; + } + mVisibilityController.setVisibility(View.INVISIBLE); + mHidden = true; + if (mHiddenCallback != null) { + mHiddenCallback.run(); + mHiddenCallback = null; + } } }; @Inject HideComplicationTouchHandler(Complication.VisibilityController visibilityController, @Named(COMPLICATIONS_RESTORE_TIMEOUT) int restoreTimeout, + @Named(COMPLICATIONS_FADE_OUT_DELAY) int fadeOutDelay, TouchInsetManager touchInsetManager, StatusBarKeyguardViewManager statusBarKeyguardViewManager, - @Main Executor executor, - @Main Handler handler) { + @Main DelayableExecutor executor, + DreamOverlayStateController overlayStateController) { mVisibilityController = visibilityController; mRestoreTimeout = restoreTimeout; + mFadeOutDelay = fadeOutDelay; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; - mHandler = handler; mTouchInsetManager = touchInsetManager; mExecutor = executor; + mOverlayStateController = overlayStateController; } @Override @@ -87,7 +116,8 @@ public class HideComplicationTouchHandler implements DreamTouchHandler { final boolean bouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing(); // If other sessions are interested in this touch, do not fade out elements. - if (session.getActiveSessionCount() > 1 || bouncerShowing) { + if (session.getActiveSessionCount() > 1 || bouncerShowing + || mOverlayStateController.areExitAnimationsRunning()) { if (DEBUG) { Log.d(TAG, "not fading. Active session count: " + session.getActiveSessionCount() + ". Bouncer showing: " + bouncerShowing); @@ -115,8 +145,11 @@ public class HideComplicationTouchHandler implements DreamTouchHandler { touchCheck.addListener(() -> { try { if (!touchCheck.get()) { - mHandler.removeCallbacks(mRestoreComplications); - mVisibilityController.setVisibility(View.INVISIBLE, true); + // Cancel all pending callbacks. + while (!mCancelCallbacks.isEmpty()) mCancelCallbacks.pop().run(); + mCancelCallbacks.add( + mExecutor.executeDelayed( + mHideComplications, mFadeOutDelay)); } else { // If a touch occurred inside the dream overlay touch insets, do not // handle the touch. @@ -130,7 +163,23 @@ public class HideComplicationTouchHandler implements DreamTouchHandler { || motionEvent.getAction() == MotionEvent.ACTION_UP) { // End session and initiate delayed reappearance of the complications. session.pop(); - mHandler.postDelayed(mRestoreComplications, mRestoreTimeout); + runAfterHidden(() -> mCancelCallbacks.add( + mExecutor.executeDelayed(mRestoreComplications, + mRestoreTimeout))); + } + }); + } + + /** + * Triggers a runnable after complications have been hidden. Will override any previously set + * runnable currently waiting for hide to happen. + */ + private void runAfterHidden(Runnable runnable) { + mExecutor.execute(() -> { + if (mHidden) { + runnable.run(); + } else { + mHiddenCallback = runnable; } }); } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 2dbbb1b3685c..784e92d37e28 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -290,7 +290,7 @@ object Flags { @Keep @JvmField val WM_ENABLE_SHELL_TRANSITIONS = - sysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", default = true) + sysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", default = false) // TODO(b/254513207): Tracking Bug @Keep diff --git a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java index 18fb423b87a5..d9bcb508c8e2 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java @@ -50,13 +50,12 @@ public class ExtensionFragmentListener<T extends FragmentBase> implements Consum @Override public void accept(T extension) { - try { - Fragment.class.cast(extension); + if (Fragment.class.isInstance(extension)) { mFragmentHostManager.getExtensionManager().setCurrentExtension(mId, mTag, mOldClass, extension.getClass().getName(), mExtension.getContext()); mOldClass = extension.getClass().getName(); - } catch (ClassCastException e) { - Log.e(TAG, extension.getClass().getName() + " must be a Fragment", e); + } else { + Log.e(TAG, extension.getClass().getName() + " must be a Fragment"); } mExtension.clearItem(true); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 663582ede385..3d976d43759c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -410,6 +410,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, private final int mDreamOpenAnimationDuration; /** + * The duration in milliseconds of the dream close animation. + */ + private final int mDreamCloseAnimationDuration; + + /** * The animation used for hiding keyguard. This is used to fetch the animation timings if * WindowManager is not providing us with them. */ @@ -1056,7 +1061,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } mUnoccludeAnimator = ValueAnimator.ofFloat(1f, 0f); - mUnoccludeAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION); + mUnoccludeAnimator.setDuration(isDream ? mDreamCloseAnimationDuration + : UNOCCLUDE_ANIMATION_DURATION); mUnoccludeAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE); mUnoccludeAnimator.addUpdateListener( animation -> { @@ -1208,6 +1214,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mDreamOpenAnimationDuration = context.getResources().getInteger( com.android.internal.R.integer.config_dreamOpenAnimationDuration); + mDreamCloseAnimationDuration = context.getResources().getInteger( + com.android.internal.R.integer.config_dreamCloseAnimationDuration); } public void userActivity() { diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java index be82b1faac8e..67e96645f9c5 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java @@ -1096,7 +1096,7 @@ public class PeopleTileViewHelper { Pair<Integer, Integer> first = emojiIndices.get(i - 1); // Check if second emoji starts right after first starts - if (second.first == first.second) { + if (Objects.equals(second.first, first.second)) { // Check if emojis in sequence are the same if (Objects.equals(emojiTexts.get(i), emojiTexts.get(i - 1))) { if (DEBUG) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 815b86e0adb8..cd130854ff3f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -132,8 +132,11 @@ public class NotificationShelf extends ActivatableNotificationView implements mPaddingBetweenElements = res.getDimensionPixelSize(R.dimen.notification_divider_height); ViewGroup.LayoutParams layoutParams = getLayoutParams(); - layoutParams.height = res.getDimensionPixelOffset(R.dimen.notification_shelf_height); - setLayoutParams(layoutParams); + final int newShelfHeight = res.getDimensionPixelOffset(R.dimen.notification_shelf_height); + if (newShelfHeight != layoutParams.height) { + layoutParams.height = newShelfHeight; + setLayoutParams(layoutParams); + } final int padding = res.getDimensionPixelOffset(R.dimen.shelf_icon_container_padding); mShelfIcons.setPadding(padding, 0, padding, 0); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt index 58738377a3db..6bd9502263ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt @@ -235,19 +235,24 @@ class LockscreenSmartspaceController @Inject constructor( ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter { override fun startIntent(view: View, intent: Intent, showOnLockscreen: Boolean) { - activityStarter.startActivity( - intent, - true, /* dismissShade */ - null, /* launch animator - looks bad with the transparent smartspace bg */ - showOnLockscreen - ) + if (showOnLockscreen) { + activityStarter.startActivity( + intent, + true, /* dismissShade */ + // launch animator - looks bad with the transparent smartspace bg + null, + true + ) + } else { + activityStarter.postStartActivityDismissingKeyguard(intent, 0) + } } override fun startPendingIntent(pi: PendingIntent, showOnLockscreen: Boolean) { if (showOnLockscreen) { pi.send() } else { - activityStarter.startPendingIntentDismissingKeyguard(pi) + activityStarter.postStartActivityDismissingKeyguard(pi) } } }) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java index 58f59be1db6f..5f6a5cb00543 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java @@ -53,6 +53,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -534,7 +535,7 @@ public class NotificationLogger implements StateListener { return; } if (loggedExpansionState != null - && state.mIsExpanded == loggedExpansionState) { + && Objects.equals(state.mIsExpanded, loggedExpansionState)) { return; } mLoggedExpansionState.put(key, state.mIsExpanded); diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt index ad09ee3c10d9..e13710786fbb 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt @@ -133,7 +133,9 @@ object UserSwitcherViewBinder { launch { viewModel.users.collect { users -> val viewPool = - view.children.filter { it.tag == USER_VIEW_TAG }.toMutableList() + gridContainerView.children + .filter { it.tag == USER_VIEW_TAG } + .toMutableList() viewPool.forEach { gridContainerView.removeView(it) flowWidget.removeView(it) diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt new file mode 100644 index 000000000000..99406ed44606 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt @@ -0,0 +1,125 @@ +package com.android.systemui.dreams + +import android.animation.Animator +import android.animation.AnimatorSet +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.dreams.complication.ComplicationHostViewController +import com.android.systemui.statusbar.BlurUtils +import com.android.systemui.util.mockito.argumentCaptor +import com.android.systemui.util.mockito.mock +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class DreamOverlayAnimationsControllerTest : SysuiTestCase() { + + companion object { + private const val DREAM_IN_BLUR_ANIMATION_DURATION = 1L + private const val DREAM_IN_BLUR_ANIMATION_DELAY = 2L + private const val DREAM_IN_COMPLICATIONS_ANIMATION_DURATION = 3L + private const val DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY = 4L + private const val DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY = 5L + private const val DREAM_OUT_TRANSLATION_Y_DISTANCE = 6 + private const val DREAM_OUT_TRANSLATION_Y_DURATION = 7L + private const val DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM = 8L + private const val DREAM_OUT_TRANSLATION_Y_DELAY_TOP = 9L + private const val DREAM_OUT_ALPHA_DURATION = 10L + private const val DREAM_OUT_ALPHA_DELAY_BOTTOM = 11L + private const val DREAM_OUT_ALPHA_DELAY_TOP = 12L + private const val DREAM_OUT_BLUR_DURATION = 13L + } + + @Mock private lateinit var mockAnimator: AnimatorSet + @Mock private lateinit var blurUtils: BlurUtils + @Mock private lateinit var hostViewController: ComplicationHostViewController + @Mock private lateinit var statusBarViewController: DreamOverlayStatusBarViewController + @Mock private lateinit var stateController: DreamOverlayStateController + private lateinit var controller: DreamOverlayAnimationsController + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + controller = + DreamOverlayAnimationsController( + blurUtils, + hostViewController, + statusBarViewController, + stateController, + DREAM_IN_BLUR_ANIMATION_DURATION, + DREAM_IN_BLUR_ANIMATION_DELAY, + DREAM_IN_COMPLICATIONS_ANIMATION_DURATION, + DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY, + DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY, + DREAM_OUT_TRANSLATION_Y_DISTANCE, + DREAM_OUT_TRANSLATION_Y_DURATION, + DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM, + DREAM_OUT_TRANSLATION_Y_DELAY_TOP, + DREAM_OUT_ALPHA_DURATION, + DREAM_OUT_ALPHA_DELAY_BOTTOM, + DREAM_OUT_ALPHA_DELAY_TOP, + DREAM_OUT_BLUR_DURATION + ) + } + + @Test + fun testExitAnimationOnEnd() { + val mockCallback: () -> Unit = mock() + + controller.startExitAnimations( + view = mock(), + doneCallback = mockCallback, + animatorBuilder = { mockAnimator } + ) + + val captor = argumentCaptor<Animator.AnimatorListener>() + verify(mockAnimator).addListener(captor.capture()) + val listener = captor.value + + verify(mockCallback, never()).invoke() + listener.onAnimationEnd(mockAnimator) + verify(mockCallback, times(1)).invoke() + } + + @Test + fun testCancellation() { + controller.startExitAnimations( + view = mock(), + doneCallback = mock(), + animatorBuilder = { mockAnimator } + ) + + verify(mockAnimator, never()).cancel() + controller.cancelAnimations() + verify(mockAnimator, times(1)).cancel() + } + + @Test + fun testExitAfterStartWillCancel() { + val mockStartAnimator: AnimatorSet = mock() + val mockExitAnimator: AnimatorSet = mock() + + controller.startEntryAnimations(view = mock(), animatorBuilder = { mockStartAnimator }) + + verify(mockStartAnimator, never()).cancel() + + controller.startExitAnimations( + view = mock(), + doneCallback = mock(), + animatorBuilder = { mockExitAnimator } + ) + + // Verify that we cancelled the start animator in favor of the exit + // animator. + verify(mockStartAnimator, times(1)).cancel() + verify(mockExitAnimator, never()).cancel() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java index 517804db2a70..73c226d11bc4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java @@ -204,7 +204,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { mController.onViewAttached(); verify(mAnimationsController).startEntryAnimations(mDreamOverlayContainerView); - verify(mAnimationsController, never()).cancelRunningEntryAnimations(); + verify(mAnimationsController, never()).cancelAnimations(); } @Test @@ -221,6 +221,6 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { mController.onViewAttached(); mController.onViewDetached(); - verify(mAnimationsController).cancelRunningEntryAnimations(); + verify(mAnimationsController).cancelAnimations(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java index f04a37f4c3fa..ffb8342a56a5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -337,4 +338,28 @@ public class DreamOverlayServiceTest extends SysuiTestCase { verify(mDreamOverlayComponent).getDreamOverlayContainerViewController(); verify(mDreamOverlayComponent).getDreamOverlayTouchMonitor(); } + + @Test + public void testWakeUp() throws RemoteException { + final IBinder proxy = mService.onBind(new Intent()); + final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy); + + // Inform the overlay service of dream starting. + overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT, + true /*shouldShowComplication*/); + mMainExecutor.runAllReady(); + + final Runnable callback = mock(Runnable.class); + mService.onWakeUp(callback); + mMainExecutor.runAllReady(); + verify(mDreamOverlayContainerViewController).wakeUp(callback, mMainExecutor); + } + + @Test + public void testWakeUpBeforeStartDoesNothing() { + final Runnable callback = mock(Runnable.class); + mService.onWakeUp(callback); + mMainExecutor.runAllReady(); + verify(mDreamOverlayContainerViewController, never()).wakeUp(callback, mMainExecutor); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java index 14a5702c8e5b..4e3aca710884 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java @@ -16,8 +16,6 @@ package com.android.systemui.dreams.touch; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; @@ -33,6 +31,7 @@ import androidx.concurrent.futures.CallbackToFutureAdapter; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.complication.Complication; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; @@ -52,6 +51,7 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) public class HideComplicationTouchHandlerTest extends SysuiTestCase { private static final int RESTORE_TIMEOUT = 1000; + private static final int HIDE_DELAY = 500; @Mock Complication.VisibilityController mVisibilityController; @@ -71,11 +71,18 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase { @Mock DreamTouchHandler.TouchSession mSession; - FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); + @Mock + DreamOverlayStateController mStateController; + + FakeSystemClock mClock; + + FakeExecutor mFakeExecutor; @Before public void setup() { MockitoAnnotations.initMocks(this); + mClock = new FakeSystemClock(); + mFakeExecutor = new FakeExecutor(mClock); } /** @@ -86,10 +93,11 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase { final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler( mVisibilityController, RESTORE_TIMEOUT, + HIDE_DELAY, mTouchInsetManager, mStatusBarKeyguardViewManager, mFakeExecutor, - mHandler); + mStateController); // Report multiple active sessions. when(mSession.getActiveSessionCount()).thenReturn(2); @@ -103,8 +111,10 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase { // Verify session end. verify(mSession).pop(); + mClock.advanceTime(HIDE_DELAY); + // Verify no interaction with visibility controller. - verify(mVisibilityController, never()).setVisibility(anyInt(), anyBoolean()); + verify(mVisibilityController, never()).setVisibility(anyInt()); } /** @@ -115,10 +125,11 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase { final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler( mVisibilityController, RESTORE_TIMEOUT, + HIDE_DELAY, mTouchInsetManager, mStatusBarKeyguardViewManager, mFakeExecutor, - mHandler); + mStateController); // Report one session. when(mSession.getActiveSessionCount()).thenReturn(1); @@ -132,8 +143,10 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase { // Verify session end. verify(mSession).pop(); + mClock.advanceTime(HIDE_DELAY); + // Verify no interaction with visibility controller. - verify(mVisibilityController, never()).setVisibility(anyInt(), anyBoolean()); + verify(mVisibilityController, never()).setVisibility(anyInt()); } /** @@ -144,10 +157,11 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase { final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler( mVisibilityController, RESTORE_TIMEOUT, + HIDE_DELAY, mTouchInsetManager, mStatusBarKeyguardViewManager, mFakeExecutor, - mHandler); + mStateController); // Report one session when(mSession.getActiveSessionCount()).thenReturn(1); @@ -177,8 +191,10 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase { // Verify session ended. verify(mSession).pop(); + mClock.advanceTime(HIDE_DELAY); + // Verify no interaction with visibility controller. - verify(mVisibilityController, never()).setVisibility(anyInt(), anyBoolean()); + verify(mVisibilityController, never()).setVisibility(anyInt()); } /** @@ -189,10 +205,11 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase { final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler( mVisibilityController, RESTORE_TIMEOUT, + HIDE_DELAY, mTouchInsetManager, mStatusBarKeyguardViewManager, mFakeExecutor, - mHandler); + mStateController); // Report one session when(mSession.getActiveSessionCount()).thenReturn(1); @@ -221,11 +238,11 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase { inputEventListenerCaptor.getValue().onInputEvent(mMotionEvent); mFakeExecutor.runAllReady(); - // Verify callback to restore visibility cancelled. - verify(mHandler).removeCallbacks(any()); - + // Verify visibility controller doesn't hide until after timeout + verify(mVisibilityController, never()).setVisibility(eq(View.INVISIBLE)); + mClock.advanceTime(HIDE_DELAY); // Verify visibility controller told to hide complications. - verify(mVisibilityController).setVisibility(eq(View.INVISIBLE), anyBoolean()); + verify(mVisibilityController).setVisibility(eq(View.INVISIBLE)); Mockito.clearInvocations(mVisibilityController, mHandler); @@ -235,11 +252,8 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase { mFakeExecutor.runAllReady(); // Verify visibility controller told to show complications. - ArgumentCaptor<Runnable> delayRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); - verify(mHandler).postDelayed(delayRunnableCaptor.capture(), - eq(Long.valueOf(RESTORE_TIMEOUT))); - delayRunnableCaptor.getValue().run(); - verify(mVisibilityController).setVisibility(eq(View.VISIBLE), anyBoolean()); + mClock.advanceTime(RESTORE_TIMEOUT); + verify(mVisibilityController).setVisibility(eq(View.VISIBLE)); // Verify session ended. verify(mSession).pop(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java index f4bc232702e8..df3a62f6cd71 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java @@ -75,7 +75,7 @@ public class ImageExporterTest extends SysuiTestCase { private static final byte[] EXIF_FILE_TAG = "Exif\u0000\u0000".getBytes(US_ASCII); private static final ZonedDateTime CAPTURE_TIME = - ZonedDateTime.of(LocalDateTime.of(2020, 12, 15, 13, 15), ZoneId.of("EST")); + ZonedDateTime.of(LocalDateTime.of(2020, 12, 15, 13, 15), ZoneId.of("America/New_York")); private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); @Mock diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java index 8525e3634e3a..592045c23372 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java @@ -245,6 +245,7 @@ final class RemoteAugmentedAutofillService }); } + @SuppressWarnings("ReturnValueIgnored") private void maybeRequestShowInlineSuggestions(int sessionId, @Nullable InlineSuggestionsRequest request, @Nullable List<Dataset> inlineSuggestionsData, @Nullable Bundle clientState, diff --git a/services/backup/java/com/android/server/backup/BackupAndRestoreFeatureFlags.java b/services/backup/java/com/android/server/backup/BackupAndRestoreFeatureFlags.java new file mode 100644 index 000000000000..042bcbd0a0bb --- /dev/null +++ b/services/backup/java/com/android/server/backup/BackupAndRestoreFeatureFlags.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.backup; + +import android.Manifest; +import android.annotation.RequiresPermission; +import android.provider.DeviceConfig; + +/** + * Retrieves values of feature flags. + * + * <p>These flags are intended to be configured server-side and their values should be set in {@link + * DeviceConfig} by a service that periodically syncs with the server. + * + * <p>This class must ensure that the namespace, flag name, and default value passed into {@link + * DeviceConfig} matches what's declared on the server. The namespace is shared for all backup and + * restore flags. + */ +public class BackupAndRestoreFeatureFlags { + private static final String NAMESPACE = "backup_and_restore"; + + private BackupAndRestoreFeatureFlags() {} + + /** Retrieves the value of the flag "backup_transport_future_timeout_millis". */ + @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) + public static long getBackupTransportFutureTimeoutMillis() { + return DeviceConfig.getLong( + NAMESPACE, + /* name= */ "backup_transport_future_timeout_millis", + /* defaultValue= */ 600000); // 10 minutes + } + + /** Retrieves the value of the flag "backup_transport_callback_timeout_millis". */ + @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) + public static long getBackupTransportCallbackTimeoutMillis() { + return DeviceConfig.getLong( + NAMESPACE, + /* name= */ "backup_transport_callback_timeout_millis", + /* defaultValue= */ 300000); // 5 minutes + } +} diff --git a/services/backup/java/com/android/server/backup/OperationStorage.java b/services/backup/java/com/android/server/backup/OperationStorage.java index 466f647fd034..8f73436d193a 100644 --- a/services/backup/java/com/android/server/backup/OperationStorage.java +++ b/services/backup/java/com/android/server/backup/OperationStorage.java @@ -153,4 +153,4 @@ public interface OperationStorage { * @return a set of operation tokens for operations in that state. */ Set<Integer> operationTokensForOpState(@OpState int state); -}; +} diff --git a/services/backup/java/com/android/server/backup/internal/LifecycleOperationStorage.java b/services/backup/java/com/android/server/backup/internal/LifecycleOperationStorage.java index 6908c60034b6..a94167eb9fa7 100644 --- a/services/backup/java/com/android/server/backup/internal/LifecycleOperationStorage.java +++ b/services/backup/java/com/android/server/backup/internal/LifecycleOperationStorage.java @@ -353,4 +353,4 @@ public class LifecycleOperationStorage implements OperationStorage { op.callback.handleCancel(cancelAll); } } -}; +} diff --git a/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java b/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java index 40d7cad9405a..21005bbf8af9 100644 --- a/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java +++ b/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java @@ -30,6 +30,7 @@ import android.util.Slog; import com.android.internal.backup.IBackupTransport; import com.android.internal.infra.AndroidFuture; +import com.android.server.backup.BackupAndRestoreFeatureFlags; import java.util.ArrayDeque; import java.util.HashSet; @@ -385,7 +386,8 @@ public class BackupTransportClient { private <T> T getFutureResult(AndroidFuture<T> future) { try { - return future.get(600, TimeUnit.SECONDS); + return future.get(BackupAndRestoreFeatureFlags.getBackupTransportFutureTimeoutMillis(), + TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException | TimeoutException | CancellationException e) { Slog.w(TAG, "Failed to get result from transport:", e); diff --git a/services/backup/java/com/android/server/backup/transport/TransportStatusCallback.java b/services/backup/java/com/android/server/backup/transport/TransportStatusCallback.java index fb98825f1343..deaa86c09b36 100644 --- a/services/backup/java/com/android/server/backup/transport/TransportStatusCallback.java +++ b/services/backup/java/com/android/server/backup/transport/TransportStatusCallback.java @@ -23,13 +23,13 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.backup.ITransportStatusCallback; +import com.android.server.backup.BackupAndRestoreFeatureFlags; public class TransportStatusCallback extends ITransportStatusCallback.Stub { private static final String TAG = "TransportStatusCallback"; - private static final int TIMEOUT_MILLIS = 300 * 1000; // 5 minutes. private static final int OPERATION_STATUS_DEFAULT = 0; - private final int mOperationTimeout; + private final long mOperationTimeout; @GuardedBy("this") private int mOperationStatus = OPERATION_STATUS_DEFAULT; @@ -37,7 +37,7 @@ public class TransportStatusCallback extends ITransportStatusCallback.Stub { private boolean mHasCompletedOperation = false; public TransportStatusCallback() { - mOperationTimeout = TIMEOUT_MILLIS; + mOperationTimeout = BackupAndRestoreFeatureFlags.getBackupTransportCallbackTimeoutMillis(); } @VisibleForTesting diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index 0f101b08ba70..08ee6d76f284 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -658,7 +658,6 @@ public final class ContentCaptureManagerService extends int sessionId, int flags, @NonNull IResultReceiver result) { Objects.requireNonNull(activityToken); Objects.requireNonNull(shareableActivityToken); - Objects.requireNonNull(sessionId); final int userId = UserHandle.getCallingUserId(); final ActivityPresentationInfo activityPresentationInfo = getAmInternal() @@ -677,7 +676,6 @@ public final class ContentCaptureManagerService extends @Override public void finishSession(int sessionId) { - Objects.requireNonNull(sessionId); final int userId = UserHandle.getCallingUserId(); synchronized (mLock) { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 7fb376522cc4..86bb699f07d2 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -23,18 +23,29 @@ import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGRO import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT; import static android.app.ActivityManager.PROCESS_STATE_RECEIVER; import static android.app.ActivityManager.PROCESS_STATE_TOP; +import static android.app.ForegroundServiceTypePolicy.FGS_TYPE_POLICY_CHECK_DEPRECATED; +import static android.app.ForegroundServiceTypePolicy.FGS_TYPE_POLICY_CHECK_DISABLED; +import static android.app.ForegroundServiceTypePolicy.FGS_TYPE_POLICY_CHECK_OK; +import static android.app.ForegroundServiceTypePolicy.FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_ENFORCED; +import static android.app.ForegroundServiceTypePolicy.FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_PERMISSIVE; +import static android.app.ForegroundServiceTypePolicy.FGS_TYPE_POLICY_CHECK_UNKNOWN; +import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST; +import static android.os.PowerExemptionManager.REASON_ACTIVE_DEVICE_ADMIN; import static android.os.PowerExemptionManager.REASON_ACTIVITY_STARTER; import static android.os.PowerExemptionManager.REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD; import static android.os.PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE; import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION; import static android.os.PowerExemptionManager.REASON_BACKGROUND_FGS_PERMISSION; +import static android.os.PowerExemptionManager.REASON_CARRIER_PRIVILEGED_APP; import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER; import static android.os.PowerExemptionManager.REASON_CURRENT_INPUT_METHOD; import static android.os.PowerExemptionManager.REASON_DENIED; import static android.os.PowerExemptionManager.REASON_DEVICE_DEMO_MODE; import static android.os.PowerExemptionManager.REASON_DEVICE_OWNER; +import static android.os.PowerExemptionManager.REASON_DISALLOW_APPS_CONTROL; +import static android.os.PowerExemptionManager.REASON_DPO_PROTECTED_APP; import static android.os.PowerExemptionManager.REASON_FGS_BINDING; import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION; import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION; @@ -45,10 +56,12 @@ import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT; import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI; import static android.os.PowerExemptionManager.REASON_PROC_STATE_TOP; import static android.os.PowerExemptionManager.REASON_PROFILE_OWNER; +import static android.os.PowerExemptionManager.REASON_ROLE_EMERGENCY; import static android.os.PowerExemptionManager.REASON_SERVICE_LAUNCH; import static android.os.PowerExemptionManager.REASON_START_ACTIVITY_FLAG; import static android.os.PowerExemptionManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION; import static android.os.PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED; +import static android.os.PowerExemptionManager.REASON_SYSTEM_MODULE; import static android.os.PowerExemptionManager.REASON_SYSTEM_UID; import static android.os.PowerExemptionManager.REASON_TEMP_ALLOWED_WHILE_IN_USE; import static android.os.PowerExemptionManager.REASON_UID_VISIBLE; @@ -63,6 +76,9 @@ import static android.os.Process.SYSTEM_UID; import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; import static com.android.internal.messages.nano.SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICE_BG_LAUNCH; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER; +import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT; import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED; import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD; import static com.android.internal.util.FrameworkStatsLog.SERVICE_REQUEST_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_HOT; @@ -94,6 +110,11 @@ import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.ForegroundServiceStartNotAllowedException; +import android.app.ForegroundServiceTypeNotAllowedException; +import android.app.ForegroundServiceTypePolicy; +import android.app.ForegroundServiceTypePolicy.ForegroundServicePolicyCheckCode; +import android.app.ForegroundServiceTypePolicy.ForegroundServiceTypePermission; +import android.app.ForegroundServiceTypePolicy.ForegroundServiceTypePolicyInfo; import android.app.IApplicationThread; import android.app.IForegroundServiceObserver; import android.app.IServiceConnection; @@ -122,6 +143,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.pm.ServiceInfo.ForegroundServiceType; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -576,6 +598,7 @@ public final class ActiveServices { getAppStateTracker().addBackgroundRestrictedAppListener(new BackgroundRestrictedListener()); mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class); setAllowListWhileInUsePermissionInFgs(); + initSystemExemptedFgsTypePermission(); } private AppStateTracker getAppStateTracker() { @@ -757,8 +780,8 @@ public final class ActiveServices { Slog.w(TAG, msg); showFgsBgRestrictedNotificationLocked(r); logFGSStateChangeLocked(r, - FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED, - 0, FGS_STOP_REASON_UNKNOWN); + FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED, + 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN); if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, callingUid)) { throw new ForegroundServiceStartNotAllowedException(msg); } @@ -1911,6 +1934,7 @@ public final class ActiveServices { ignoreForeground = true; } + int fgsTypeCheckCode = FGS_TYPE_POLICY_CHECK_UNKNOWN; if (!ignoreForeground) { if (r.mStartForegroundCount == 0) { /* @@ -1969,13 +1993,49 @@ public final class ActiveServices { updateServiceForegroundLocked(psr, true); ignoreForeground = true; logFGSStateChangeLocked(r, - FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED, - 0, FGS_STOP_REASON_UNKNOWN); + FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED, + 0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN); if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, r.appInfo.uid)) { throw new ForegroundServiceStartNotAllowedException(msg); } } + + if (!ignoreForeground) { + Pair<Integer, RuntimeException> fgsTypeResult = null; + if (foregroundServiceType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) { + fgsTypeResult = validateForegroundServiceType(r, + foregroundServiceType, + ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE); + } else { + int fgsTypes = foregroundServiceType; + // If the service has declared some unknown types which might be coming + // from future releases, and if it also comes with the "specialUse", + // then it'll be deemed as the "specialUse" and we ignore this + // unknown type. Otherwise, it'll be treated as an invalid type. + int defaultFgsTypes = (foregroundServiceType + & ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE) != 0 + ? ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE + : ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE; + for (int serviceType = Integer.highestOneBit(fgsTypes); + serviceType != 0; + serviceType = Integer.highestOneBit(fgsTypes)) { + fgsTypeResult = validateForegroundServiceType(r, + serviceType, defaultFgsTypes); + fgsTypes &= ~serviceType; + if (fgsTypeResult.first != FGS_TYPE_POLICY_CHECK_OK) { + break; + } + } + } + fgsTypeCheckCode = fgsTypeResult.first; + if (fgsTypeResult.second != null) { + logFGSStateChangeLocked(r, + FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED, + 0, FGS_STOP_REASON_UNKNOWN, fgsTypeResult.first); + throw fgsTypeResult.second; + } + } } // Apps under strict background restrictions simply don't get to have foreground @@ -2044,8 +2104,8 @@ public final class ActiveServices { registerAppOpCallbackLocked(r); mAm.updateForegroundServiceUsageStats(r.name, r.userId, true); logFGSStateChangeLocked(r, - FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER, - 0, FGS_STOP_REASON_UNKNOWN); + FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER, + 0, FGS_STOP_REASON_UNKNOWN, fgsTypeCheckCode); updateNumForegroundServicesLocked(); } // Even if the service is already a FGS, we need to update the notification, @@ -2126,10 +2186,11 @@ public final class ActiveServices { AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null); unregisterAppOpCallbackLocked(r); logFGSStateChangeLocked(r, - FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT, + FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT, r.mFgsExitTime > r.mFgsEnterTime ? (int) (r.mFgsExitTime - r.mFgsEnterTime) : 0, - FGS_STOP_REASON_STOP_FOREGROUND); + FGS_STOP_REASON_STOP_FOREGROUND, + FGS_TYPE_POLICY_CHECK_UNKNOWN); r.mFgsNotificationWasDeferred = false; signalForegroundServiceObserversLocked(r); resetFgsRestrictionLocked(r); @@ -2165,6 +2226,118 @@ public final class ActiveServices { return now < eligible; } + /** + * Validate if the given service can start a foreground service with given type. + * + * @return A pair, where the first parameter is the result code and second is the exception + * object if it fails to start a foreground service with given type. + */ + @NonNull + private Pair<Integer, RuntimeException> validateForegroundServiceType(ServiceRecord r, + @ForegroundServiceType int type, + @ForegroundServiceType int defaultToType) { + final ForegroundServiceTypePolicy policy = ForegroundServiceTypePolicy.getDefaultPolicy(); + final ForegroundServiceTypePolicyInfo policyInfo = + policy.getForegroundServiceTypePolicyInfo(type, defaultToType); + final @ForegroundServicePolicyCheckCode int code = policy.checkForegroundServiceTypePolicy( + mAm.mContext, r.packageName, r.app.uid, r.app.getPid(), + r.mAllowWhileInUsePermissionInFgs, policyInfo); + RuntimeException exception = null; + switch (code) { + case FGS_TYPE_POLICY_CHECK_DEPRECATED: { + final String msg = "Starting FGS with type " + + ServiceInfo.foregroundServiceTypeToLabel(type) + + " code=" + code + + " callerApp=" + r.app + + " targetSDK=" + r.app.info.targetSdkVersion; + Slog.wtfQuiet(TAG, msg); + Slog.w(TAG, msg); + } break; + case FGS_TYPE_POLICY_CHECK_DISABLED: { + exception = new ForegroundServiceTypeNotAllowedException( + "Starting FGS with type " + + ServiceInfo.foregroundServiceTypeToLabel(type) + + " callerApp=" + r.app + + " targetSDK=" + r.app.info.targetSdkVersion + + " has been prohibited"); + } break; + case FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_PERMISSIVE: { + final String msg = "Starting FGS with type " + + ServiceInfo.foregroundServiceTypeToLabel(type) + + " code=" + code + + " callerApp=" + r.app + + " targetSDK=" + r.app.info.targetSdkVersion + + " requiredPermissions=" + policyInfo.toPermissionString(); + Slog.wtfQuiet(TAG, msg); + Slog.w(TAG, msg); + } break; + case FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_ENFORCED: { + exception = new SecurityException("Starting FGS with type " + + ServiceInfo.foregroundServiceTypeToLabel(type) + + " callerApp=" + r.app + + " targetSDK=" + r.app.info.targetSdkVersion + + " requires permissions: " + + policyInfo.toPermissionString()); + } break; + case FGS_TYPE_POLICY_CHECK_OK: + default: + break; + } + return Pair.create(code, exception); + } + + private class SystemExemptedFgsTypePermission extends ForegroundServiceTypePermission { + SystemExemptedFgsTypePermission() { + super("System exempted"); + } + + @Override + public int checkPermission(@NonNull Context context, int callerUid, int callerPid, + @NonNull String packageName, boolean allowWhileInUse) { + final AppRestrictionController appRestrictionController = mAm.mAppRestrictionController; + @ReasonCode int reason = appRestrictionController + .getPotentialSystemExemptionReason(callerUid); + if (reason == REASON_DENIED) { + reason = appRestrictionController + .getPotentialSystemExemptionReason(callerUid, packageName); + if (reason == REASON_DENIED) { + reason = appRestrictionController + .getPotentialUserAllowedExemptionReason(callerUid, packageName); + } + } + switch (reason) { + case REASON_SYSTEM_UID: + case REASON_SYSTEM_ALLOW_LISTED: + case REASON_DEVICE_DEMO_MODE: + case REASON_DISALLOW_APPS_CONTROL: + case REASON_DEVICE_OWNER: + case REASON_PROFILE_OWNER: + case REASON_PROC_STATE_PERSISTENT: + case REASON_PROC_STATE_PERSISTENT_UI: + case REASON_SYSTEM_MODULE: + case REASON_CARRIER_PRIVILEGED_APP: + case REASON_DPO_PROTECTED_APP: + case REASON_ACTIVE_DEVICE_ADMIN: + case REASON_ROLE_EMERGENCY: + case REASON_ALLOWLISTED_PACKAGE: + return PERMISSION_GRANTED; + default: + return PERMISSION_DENIED; + } + } + } + + private void initSystemExemptedFgsTypePermission() { + final ForegroundServiceTypePolicy policy = ForegroundServiceTypePolicy.getDefaultPolicy(); + final ForegroundServiceTypePolicyInfo policyInfo = + policy.getForegroundServiceTypePolicyInfo( + ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED, + ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE); + if (policyInfo != null) { + policyInfo.setCustomPermission(new SystemExemptedFgsTypePermission()); + } + } + ServiceNotificationPolicy applyForegroundServiceNotificationLocked(Notification notification, final String tag, final int id, final String pkg, final int userId) { // By nature of the FGS API, all FGS notifications have a null tag @@ -4777,10 +4950,11 @@ public final class ActiveServices { unregisterAppOpCallbackLocked(r); r.mFgsExitTime = SystemClock.uptimeMillis(); logFGSStateChangeLocked(r, - FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT, + FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT, r.mFgsExitTime > r.mFgsEnterTime ? (int) (r.mFgsExitTime - r.mFgsEnterTime) : 0, - FGS_STOP_REASON_STOP_SERVICE); + FGS_STOP_REASON_STOP_SERVICE, + FGS_TYPE_POLICY_CHECK_UNKNOWN); mAm.updateForegroundServiceUsageStats(r.name, r.userId, false); } @@ -7020,17 +7194,20 @@ public final class ActiveServices { * @param r ServiceRecord * @param state one of ENTER/EXIT/DENIED event. * @param durationMs Only meaningful for EXIT event, the duration from ENTER and EXIT state. + * @param fgsStopReason why was this FGS stopped. + * @param fgsTypeCheckCode The FGS type policy check result. */ private void logFGSStateChangeLocked(ServiceRecord r, int state, int durationMs, - @FgsStopReason int fgsStopReason) { + @FgsStopReason int fgsStopReason, + @ForegroundServicePolicyCheckCode int fgsTypeCheckCode) { if (!ActivityManagerUtils.shouldSamplePackageForAtom( r.packageName, mAm.mConstants.mFgsAtomSampleRate)) { return; } boolean allowWhileInUsePermissionInFgs; @PowerExemptionManager.ReasonCode int fgsStartReasonCode; - if (state == FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER - || state == FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT) { + if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER + || state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT) { allowWhileInUsePermissionInFgs = r.mAllowWhileInUsePermissionInFgsAtEntering; fgsStartReasonCode = r.mAllowStartForegroundAtEntering; } else { @@ -7056,14 +7233,15 @@ public final class ActiveServices { r.mStartForegroundCount, ActivityManagerUtils.hashComponentNameForAtom(r.shortInstanceName), r.mFgsHasNotificationPermission, - r.foregroundServiceType); + r.foregroundServiceType, + fgsTypeCheckCode); int event = 0; - if (state == FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER) { + if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER) { event = EventLogTags.AM_FOREGROUND_SERVICE_START; - } else if (state == FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT) { + } else if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT) { event = EventLogTags.AM_FOREGROUND_SERVICE_STOP; - } else if (state == FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED) { + } else if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED) { event = EventLogTags.AM_FOREGROUND_SERVICE_DENIED; } else { // Unknown event. diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 16fe121fecb7..003f7f0d88fb 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -249,6 +249,18 @@ final class ActivityManagerConstants extends ContentObserver { private static final String KEY_MAX_PHANTOM_PROCESSES = "max_phantom_processes"; /** + * Enables proactive killing of cached apps + */ + private static final String KEY_PROACTIVE_KILLS_ENABLED = "proactive_kills_enabled"; + + /** + * Trim LRU cached app when swap falls below this minimum percentage. + * + * Depends on KEY_PROACTIVE_KILLS_ENABLED + */ + private static final String KEY_LOW_SWAP_THRESHOLD_PERCENT = "low_swap_threshold_percent"; + + /** * Default value for mFlagBackgroundActivityStartsEnabled if not explicitly set in * Settings.Global. This allows it to be set experimentally unless it has been * enabled/disabled in developer options. Defaults to false. @@ -874,6 +886,10 @@ final class ActivityManagerConstants extends ContentObserver { */ private static final long DEFAULT_MIN_ASSOC_LOG_DURATION = 5 * 60 * 1000; // 5 mins + private static final boolean DEFAULT_PROACTIVE_KILLS_ENABLED = false; + + private static final float DEFAULT_LOW_SWAP_THRESHOLD_PERCENT = 0.10f; + private static final String KEY_MIN_ASSOC_LOG_DURATION = "min_assoc_log_duration"; public static long MIN_ASSOC_LOG_DURATION = DEFAULT_MIN_ASSOC_LOG_DURATION; @@ -904,6 +920,8 @@ final class ActivityManagerConstants extends ContentObserver { public static boolean BINDER_HEAVY_HITTER_AUTO_SAMPLER_ENABLED; public static int BINDER_HEAVY_HITTER_AUTO_SAMPLER_BATCHSIZE; public static float BINDER_HEAVY_HITTER_AUTO_SAMPLER_THRESHOLD; + public static boolean PROACTIVE_KILLS_ENABLED = DEFAULT_PROACTIVE_KILLS_ENABLED; + public static float LOW_SWAP_THRESHOLD_PERCENT = DEFAULT_LOW_SWAP_THRESHOLD_PERCENT; private final OnPropertiesChangedListener mOnDeviceConfigChangedListener = new OnPropertiesChangedListener() { @@ -1040,6 +1058,12 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_MAX_SERVICE_CONNECTIONS_PER_PROCESS: updateMaxServiceConnectionsPerProcess(); break; + case KEY_PROACTIVE_KILLS_ENABLED: + updateProactiveKillsEnabled(); + break; + case KEY_LOW_SWAP_THRESHOLD_PERCENT: + updateLowSwapThresholdPercent(); + break; default: break; } @@ -1660,6 +1684,20 @@ final class ActivityManagerConstants extends ContentObserver { CUR_TRIM_CACHED_PROCESSES = (MAX_CACHED_PROCESSES-rawMaxEmptyProcesses)/3; } + private void updateProactiveKillsEnabled() { + PROACTIVE_KILLS_ENABLED = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_PROACTIVE_KILLS_ENABLED, + DEFAULT_PROACTIVE_KILLS_ENABLED); + } + + private void updateLowSwapThresholdPercent() { + LOW_SWAP_THRESHOLD_PERCENT = DeviceConfig.getFloat( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_LOW_SWAP_THRESHOLD_PERCENT, + DEFAULT_LOW_SWAP_THRESHOLD_PERCENT); + } + private void updateMinAssocLogDuration() { MIN_ASSOC_LOG_DURATION = DeviceConfig.getLong( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_MIN_ASSOC_LOG_DURATION, @@ -1860,6 +1898,10 @@ final class ActivityManagerConstants extends ContentObserver { pw.print("="); pw.println(mNetworkAccessTimeoutMs); pw.print(" "); pw.print(KEY_MAX_SERVICE_CONNECTIONS_PER_PROCESS); pw.print("="); pw.println(mMaxServiceConnectionsPerProcess); + pw.print(" "); pw.print(KEY_PROACTIVE_KILLS_ENABLED); + pw.print("="); pw.println(PROACTIVE_KILLS_ENABLED); + pw.print(" "); pw.print(KEY_LOW_SWAP_THRESHOLD_PERCENT); + pw.print("="); pw.println(LOW_SWAP_THRESHOLD_PERCENT); pw.println(); if (mOverrideMaxCachedProcesses >= 0) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7d640772a4be..d44b727d724b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -378,12 +378,10 @@ import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.MemInfoReader; import com.android.internal.util.Preconditions; -import com.android.internal.util.function.DecFunction; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuintFunction; -import com.android.internal.util.function.TriFunction; import com.android.internal.util.function.UndecFunction; import com.android.server.AlarmManagerInternal; import com.android.server.BootReceiver; @@ -18904,19 +18902,20 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public SyncNotedAppOp startProxyOperation(int code, + public SyncNotedAppOp startProxyOperation(@NonNull IBinder clientId, int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags, int attributionChainId, - @NonNull DecFunction<Integer, AttributionSource, Boolean, Boolean, String, Boolean, - Boolean, Integer, Integer, Integer, SyncNotedAppOp> superImpl) { + @NonNull UndecFunction<IBinder, Integer, AttributionSource, + Boolean, Boolean, String, Boolean, Boolean, Integer, Integer, Integer, + SyncNotedAppOp> superImpl) { if (attributionSource.getUid() == mTargetUid && isTargetOp(code)) { final int shellUid = UserHandle.getUid(UserHandle.getUserId( attributionSource.getUid()), Process.SHELL_UID); final long identity = Binder.clearCallingIdentity(); try { - return superImpl.apply(code, new AttributionSource(shellUid, + return superImpl.apply(clientId, code, new AttributionSource(shellUid, "com.android.shell", attributionSource.getAttributionTag(), attributionSource.getToken(), attributionSource.getNext()), startIfModeDefault, shouldCollectAsyncNotedOp, message, @@ -18926,21 +18925,22 @@ public class ActivityManagerService extends IActivityManager.Stub Binder.restoreCallingIdentity(identity); } } - return superImpl.apply(code, attributionSource, startIfModeDefault, + return superImpl.apply(clientId, code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); } @Override - public void finishProxyOperation(int code, @NonNull AttributionSource attributionSource, - boolean skipProxyOperation, @NonNull TriFunction<Integer, AttributionSource, - Boolean, Void> superImpl) { + public void finishProxyOperation(@NonNull IBinder clientId, int code, + @NonNull AttributionSource attributionSource, boolean skipProxyOperation, + @NonNull QuadFunction<IBinder, Integer, AttributionSource, Boolean, + Void> superImpl) { if (attributionSource.getUid() == mTargetUid && isTargetOp(code)) { final int shellUid = UserHandle.getUid(UserHandle.getUserId( attributionSource.getUid()), Process.SHELL_UID); final long identity = Binder.clearCallingIdentity(); try { - superImpl.apply(code, new AttributionSource(shellUid, + superImpl.apply(clientId, code, new AttributionSource(shellUid, "com.android.shell", attributionSource.getAttributionTag(), attributionSource.getToken(), attributionSource.getNext()), skipProxyOperation); @@ -18948,7 +18948,7 @@ public class ActivityManagerService extends IActivityManager.Stub Binder.restoreCallingIdentity(identity); } } - superImpl.apply(code, attributionSource, skipProxyOperation); + superImpl.apply(clientId, code, attributionSource, skipProxyOperation); } private boolean isTargetOp(int code) { diff --git a/services/core/java/com/android/server/am/AppFGSTracker.java b/services/core/java/com/android/server/am/AppFGSTracker.java index 50515cd923d1..1f98aba5bbd7 100644 --- a/services/core/java/com/android/server/am/AppFGSTracker.java +++ b/services/core/java/com/android/server/am/AppFGSTracker.java @@ -16,10 +16,10 @@ package com.android.server.am; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPES_MAX_INDEX; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE; -import static android.content.pm.ServiceInfo.NUM_OF_FOREGROUND_SERVICE_TYPES; import static android.content.pm.ServiceInfo.foregroundServiceTypeToLabel; import static android.os.PowerExemptionManager.REASON_DENIED; @@ -645,7 +645,7 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac PackageDurations(int uid, String packageName, MaxTrackingDurationConfig maxTrackingDurationConfig, AppFGSTracker tracker) { - super(uid, packageName, NUM_OF_FOREGROUND_SERVICE_TYPES + 1, TAG, + super(uid, packageName, FOREGROUND_SERVICE_TYPES_MAX_INDEX + 1, TAG, maxTrackingDurationConfig); mEvents[DEFAULT_INDEX] = new LinkedList<>(); mTracker = tracker; diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java index ba1c3b34d7a2..6abf6d8e9eea 100644 --- a/services/core/java/com/android/server/am/AppRestrictionController.java +++ b/services/core/java/com/android/server/am/AppRestrictionController.java @@ -2784,6 +2784,37 @@ public final class AppRestrictionController { */ @ReasonCode int getBackgroundRestrictionExemptionReason(int uid) { + @ReasonCode int reason = getPotentialSystemExemptionReason(uid); + if (reason != REASON_DENIED) { + return reason; + } + final String[] packages = mInjector.getPackageManager().getPackagesForUid(uid); + if (packages != null) { + // Check each packages to see if any of them is in the "fixed" exemption cases. + for (String pkg : packages) { + reason = getPotentialSystemExemptionReason(uid, pkg); + if (reason != REASON_DENIED) { + return reason; + } + } + // Loop the packages again, and check the user-configurable exemptions. + for (String pkg : packages) { + reason = getPotentialUserAllowedExemptionReason(uid, pkg); + if (reason != REASON_DENIED) { + return reason; + } + } + } + return REASON_DENIED; + } + + /** + * @param uid The uid to check. + * @return The potential exemption reason of the given uid. The caller must decide + * whether or not it should be exempted. + */ + @ReasonCode + int getPotentialSystemExemptionReason(int uid) { if (UserHandle.isCore(uid)) { return REASON_SYSTEM_UID; } @@ -2811,37 +2842,51 @@ public final class AppRestrictionController { } else if (uidProcState <= PROCESS_STATE_PERSISTENT_UI) { return REASON_PROC_STATE_PERSISTENT_UI; } - final String[] packages = mInjector.getPackageManager().getPackagesForUid(uid); - if (packages != null) { - final AppOpsManager appOpsManager = mInjector.getAppOpsManager(); - final PackageManagerInternal pm = mInjector.getPackageManagerInternal(); - final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal(); - // Check each packages to see if any of them is in the "fixed" exemption cases. - for (String pkg : packages) { - if (isSystemModule(pkg)) { - return REASON_SYSTEM_MODULE; - } else if (isCarrierApp(pkg)) { - return REASON_CARRIER_PRIVILEGED_APP; - } else if (isExemptedFromSysConfig(pkg)) { - return REASON_SYSTEM_ALLOW_LISTED; - } else if (mConstantsObserver.mBgRestrictionExemptedPackages.contains(pkg)) { - return REASON_SYSTEM_ALLOW_LISTED; - } else if (pm.isPackageStateProtected(pkg, userId)) { - return REASON_DPO_PROTECTED_APP; - } else if (appStandbyInternal.isActiveDeviceAdmin(pkg, userId)) { - return REASON_ACTIVE_DEVICE_ADMIN; - } - } - // Loop the packages again, and check the user-configurable exemptions. - for (String pkg : packages) { - if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, - uid, pkg) == AppOpsManager.MODE_ALLOWED) { - return REASON_OP_ACTIVATE_VPN; - } else if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, - uid, pkg) == AppOpsManager.MODE_ALLOWED) { - return REASON_OP_ACTIVATE_PLATFORM_VPN; - } - } + return REASON_DENIED; + } + + /** + * @param uid The uid to check. + * @param pkgName The package name to check. + * @return The potential system-fixed exemption reason of the given uid/package. The caller + * must decide whether or not it should be exempted. + */ + @ReasonCode + int getPotentialSystemExemptionReason(int uid, String pkg) { + final PackageManagerInternal pm = mInjector.getPackageManagerInternal(); + final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal(); + final int userId = UserHandle.getUserId(uid); + if (isSystemModule(pkg)) { + return REASON_SYSTEM_MODULE; + } else if (isCarrierApp(pkg)) { + return REASON_CARRIER_PRIVILEGED_APP; + } else if (isExemptedFromSysConfig(pkg)) { + return REASON_SYSTEM_ALLOW_LISTED; + } else if (mConstantsObserver.mBgRestrictionExemptedPackages.contains(pkg)) { + return REASON_SYSTEM_ALLOW_LISTED; + } else if (pm.isPackageStateProtected(pkg, userId)) { + return REASON_DPO_PROTECTED_APP; + } else if (appStandbyInternal.isActiveDeviceAdmin(pkg, userId)) { + return REASON_ACTIVE_DEVICE_ADMIN; + } + return REASON_DENIED; + } + + /** + * @param uid The uid to check. + * @param pkgName The package name to check. + * @return The potential user-allowed exemption reason of the given uid/package. The caller + * must decide whether or not it should be exempted. + */ + @ReasonCode + int getPotentialUserAllowedExemptionReason(int uid, String pkg) { + final AppOpsManager appOpsManager = mInjector.getAppOpsManager(); + if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, + uid, pkg) == AppOpsManager.MODE_ALLOWED) { + return REASON_OP_ACTIVATE_VPN; + } else if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, + uid, pkg) == AppOpsManager.MODE_ALLOWED) { + return REASON_OP_ACTIVATE_PLATFORM_VPN; } if (isRoleHeldByUid(RoleManager.ROLE_DIALER, uid)) { return REASON_ROLE_DIALER; @@ -2852,6 +2897,7 @@ public final class AppRestrictionController { if (isOnDeviceIdleAllowlist(uid)) { return REASON_ALLOWLISTED_PACKAGE; } + final ActivityManagerInternal am = mInjector.getActivityManagerInternal(); if (am.isAssociatedCompanionApp(UserHandle.getUserId(uid), uid)) { return REASON_COMPANION_DEVICE_MANAGER; } diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index ce78d1b73e68..008d95a51cd9 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -239,7 +239,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } case MSG_DELIVERY_TIMEOUT_SOFT: { synchronized (mService) { - deliveryTimeoutSoftLocked((BroadcastProcessQueue) msg.obj); + deliveryTimeoutSoftLocked((BroadcastProcessQueue) msg.obj, msg.arg1); } return true; } @@ -746,9 +746,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) { queue.lastCpuDelayTime = queue.app.getCpuDelayTime(); - final long timeout = r.isForeground() ? mFgConstants.TIMEOUT : mBgConstants.TIMEOUT; - mLocalHandler.sendMessageDelayed( - Message.obtain(mLocalHandler, MSG_DELIVERY_TIMEOUT_SOFT, queue), timeout); + final int softTimeoutMillis = (int) (r.isForeground() ? mFgConstants.TIMEOUT + : mBgConstants.TIMEOUT); + mLocalHandler.sendMessageDelayed(Message.obtain(mLocalHandler, + MSG_DELIVERY_TIMEOUT_SOFT, softTimeoutMillis, 0, queue), softTimeoutMillis); } if (r.allowBackgroundActivityStarts) { @@ -835,15 +836,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue { r.resultTo = null; } - private void deliveryTimeoutSoftLocked(@NonNull BroadcastProcessQueue queue) { + private void deliveryTimeoutSoftLocked(@NonNull BroadcastProcessQueue queue, + int softTimeoutMillis) { if (queue.app != null) { // Instead of immediately triggering an ANR, extend the timeout by // the amount of time the process was runnable-but-waiting; we're // only willing to do this once before triggering an hard ANR final long cpuDelayTime = queue.app.getCpuDelayTime() - queue.lastCpuDelayTime; - final long timeout = MathUtils.constrain(cpuDelayTime, 0, mConstants.TIMEOUT); + final long hardTimeoutMillis = MathUtils.constrain(cpuDelayTime, 0, softTimeoutMillis); mLocalHandler.sendMessageDelayed( - Message.obtain(mLocalHandler, MSG_DELIVERY_TIMEOUT_HARD, queue), timeout); + Message.obtain(mLocalHandler, MSG_DELIVERY_TIMEOUT_HARD, queue), + hardTimeoutMillis); } else { deliveryTimeoutHardLocked(queue); } diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 2d7b0dc7b536..e34cd12d0ec3 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -845,7 +845,7 @@ public final class CachedAppOptimizer { /** * Retrieves the free swap percentage. */ - static private native double getFreeSwapPercent(); + static native double getFreeSwapPercent(); /** * Retrieves the total used physical ZRAM diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 68e5a5df9562..eb2b7d493251 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1118,6 +1118,12 @@ public class OomAdjuster { private long mNextNoKillDebugMessageTime; + private double mLastFreeSwapPercent = 1.00; + + private static double getFreeSwapPercent() { + return CachedAppOptimizer.getFreeSwapPercent(); + } + @GuardedBy({"mService", "mProcLock"}) private boolean updateAndTrimProcessLSP(final long now, final long nowElapsed, final long oldTime, final ActiveUids activeUids, @OomAdjReason int oomAdjReason) { @@ -1142,6 +1148,11 @@ public class OomAdjuster { int numEmpty = 0; int numTrimming = 0; + boolean proactiveKillsEnabled = mConstants.PROACTIVE_KILLS_ENABLED; + double lowSwapThresholdPercent = mConstants.LOW_SWAP_THRESHOLD_PERCENT; + double freeSwapPercent = proactiveKillsEnabled ? getFreeSwapPercent() : 1.00; + ProcessRecord lruCachedApp = null; + for (int i = numLru - 1; i >= 0; i--) { ProcessRecord app = lruList.get(i); final ProcessStateRecord state = app.mState; @@ -1179,6 +1190,8 @@ public class OomAdjuster { ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_TOO_MANY_CACHED, true); + } else if (proactiveKillsEnabled) { + lruCachedApp = app; } break; case PROCESS_STATE_CACHED_EMPTY: @@ -1198,6 +1211,8 @@ public class OomAdjuster { ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_TOO_MANY_EMPTY, true); + } else if (proactiveKillsEnabled) { + lruCachedApp = app; } } break; @@ -1229,6 +1244,20 @@ public class OomAdjuster { } } + if (proactiveKillsEnabled // Proactive kills enabled? + && doKillExcessiveProcesses // Should kill excessive processes? + && freeSwapPercent < lowSwapThresholdPercent // Swap below threshold? + && lruCachedApp != null // If no cached app, let LMKD decide + // If swap is non-decreasing, give reclaim a chance to catch up + && freeSwapPercent < mLastFreeSwapPercent) { + lruCachedApp.killLocked("swap low and too many cached", + ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_TOO_MANY_CACHED, + true); + } + + mLastFreeSwapPercent = freeSwapPercent; + return mService.mAppProfiler.updateLowMemStateLSP(numCached, numEmpty, numTrimming); } diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index 31d707da014f..64f2aa38e5b1 100644 --- a/services/core/java/com/android/server/app/GameManagerService.java +++ b/services/core/java/com/android/server/app/GameManagerService.java @@ -1314,16 +1314,9 @@ public final class GameManagerService extends IGameManagerService.Stub { void onUserSwitching(TargetUser from, TargetUser to) { final int toUserId = to.getUserIdentifier(); - if (from != null) { - synchronized (mLock) { - final int fromUserId = from.getUserIdentifier(); - if (mSettings.containsKey(fromUserId)) { - sendUserMessage(fromUserId, REMOVE_SETTINGS, "ON_USER_SWITCHING", - 0 /*delayMillis*/); - } - } - } - + // we want to re-populate the setting when switching user as the device config may have + // changed, which will only update for the previous user, see + // DeviceConfigListener#onPropertiesChanged. sendUserMessage(toUserId, POPULATE_GAME_MODE_SETTINGS, "ON_USER_SWITCHING", 0 /*delayMillis*/); @@ -1392,8 +1385,9 @@ public final class GameManagerService extends IGameManagerService.Stub { Slog.v(TAG, "Package configuration not found for " + packageName); return; } + } else { + updateFps(packageConfig, packageName, gameMode, userId); } - updateFps(packageConfig, packageName, gameMode, userId); updateUseAngle(packageName, gameMode); } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index a58583c53321..7e00c3212c95 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -2920,18 +2920,18 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } @Override - public SyncNotedAppOp startProxyOperation(int code, + public SyncNotedAppOp startProxyOperation(@NonNull IBinder clientId, int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags, int attributionChainId) { - return mCheckOpsDelegateDispatcher.startProxyOperation(code, attributionSource, + return mCheckOpsDelegateDispatcher.startProxyOperation(clientId, code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); } - private SyncNotedAppOp startProxyOperationImpl(int code, + private SyncNotedAppOp startProxyOperationImpl(@NonNull IBinder clientId, int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags @@ -2940,11 +2940,9 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch final int proxyUid = attributionSource.getUid(); final String proxyPackageName = attributionSource.getPackageName(); final String proxyAttributionTag = attributionSource.getAttributionTag(); - final IBinder proxyToken = attributionSource.getToken(); final int proxiedUid = attributionSource.getNextUid(); final String proxiedPackageName = attributionSource.getNextPackageName(); final String proxiedAttributionTag = attributionSource.getNextAttributionTag(); - final IBinder proxiedToken = attributionSource.getNextToken(); verifyIncomingProxyUid(attributionSource); verifyIncomingOp(code); @@ -2986,7 +2984,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch if (!skipProxyOperation) { // Test if the proxied operation will succeed before starting the proxy operation - final SyncNotedAppOp testProxiedOp = startOperationUnchecked(proxiedToken, code, + final SyncNotedAppOp testProxiedOp = startOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag, proxyUid, resolvedProxyPackageName, proxyAttributionTag, proxiedFlags, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, @@ -2998,7 +2996,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY; - final SyncNotedAppOp proxyAppOp = startOperationUnchecked(proxyToken, code, proxyUid, + final SyncNotedAppOp proxyAppOp = startOperationUnchecked(clientId, code, proxyUid, resolvedProxyPackageName, proxyAttributionTag, Process.INVALID_UID, null, null, proxyFlags, startIfModeDefault, !isProxyTrusted, "proxy " + message, shouldCollectMessage, proxyAttributionFlags, attributionChainId, @@ -3008,7 +3006,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } } - return startOperationUnchecked(proxiedToken, code, proxiedUid, resolvedProxiedPackageName, + return startOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag, proxyUid, resolvedProxyPackageName, proxyAttributionTag, proxiedFlags, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, proxiedAttributionFlags, attributionChainId, @@ -3151,22 +3149,20 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } @Override - public void finishProxyOperation(int code, @NonNull AttributionSource attributionSource, - boolean skipProxyOperation) { - mCheckOpsDelegateDispatcher.finishProxyOperation(code, attributionSource, + public void finishProxyOperation(@NonNull IBinder clientId, int code, + @NonNull AttributionSource attributionSource, boolean skipProxyOperation) { + mCheckOpsDelegateDispatcher.finishProxyOperation(clientId, code, attributionSource, skipProxyOperation); } - private Void finishProxyOperationImpl(int code, @NonNull AttributionSource attributionSource, - boolean skipProxyOperation) { + private Void finishProxyOperationImpl(IBinder clientId, int code, + @NonNull AttributionSource attributionSource, boolean skipProxyOperation) { final int proxyUid = attributionSource.getUid(); final String proxyPackageName = attributionSource.getPackageName(); final String proxyAttributionTag = attributionSource.getAttributionTag(); - final IBinder proxyToken = attributionSource.getToken(); final int proxiedUid = attributionSource.getNextUid(); final String proxiedPackageName = attributionSource.getNextPackageName(); final String proxiedAttributionTag = attributionSource.getNextAttributionTag(); - final IBinder proxiedToken = attributionSource.getNextToken(); skipProxyOperation = skipProxyOperation && isCallerAndAttributionTrusted(attributionSource); @@ -3185,7 +3181,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } if (!skipProxyOperation) { - finishOperationUnchecked(proxyToken, code, proxyUid, resolvedProxyPackageName, + finishOperationUnchecked(clientId, code, proxyUid, resolvedProxyPackageName, proxyAttributionTag); } @@ -3195,7 +3191,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch return null; } - finishOperationUnchecked(proxiedToken, code, proxiedUid, resolvedProxiedPackageName, + finishOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag); return null; @@ -6262,7 +6258,6 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch Objects.requireNonNull(stackTrace); Preconditions.checkArgument(op >= 0); Preconditions.checkArgument(op < AppOpsManager._NUM_OP); - Objects.requireNonNull(version); NoteOpTrace noteOpTrace = new NoteOpTrace(stackTrace, op, packageName, version); @@ -6436,42 +6431,42 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch attributionFlags, attributionChainId, AppOpsService.this::startOperationImpl); } - public SyncNotedAppOp startProxyOperation(int code, + public SyncNotedAppOp startProxyOperation(@NonNull IBinder clientId, int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags, int attributionChainId) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { - return mPolicy.startProxyOperation(code, attributionSource, + return mPolicy.startProxyOperation(clientId, code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags, attributionChainId, this::startDelegateProxyOperationImpl); } else { - return mPolicy.startProxyOperation(code, attributionSource, + return mPolicy.startProxyOperation(clientId, code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags, attributionChainId, AppOpsService.this::startProxyOperationImpl); } } else if (mCheckOpsDelegate != null) { - return startDelegateProxyOperationImpl(code, attributionSource, + return startDelegateProxyOperationImpl(clientId, code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); } - return startProxyOperationImpl(code, attributionSource, startIfModeDefault, + return startProxyOperationImpl(clientId, code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); } - private SyncNotedAppOp startDelegateProxyOperationImpl(int code, + private SyncNotedAppOp startDelegateProxyOperationImpl(@NonNull IBinder clientId, int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlsgs, int attributionChainId) { - return mCheckOpsDelegate.startProxyOperation(code, attributionSource, + return mCheckOpsDelegate.startProxyOperation(clientId, code, attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlsgs, attributionChainId, AppOpsService.this::startProxyOperationImpl); @@ -6500,27 +6495,28 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch AppOpsService.this::finishOperationImpl); } - public void finishProxyOperation(int code, + public void finishProxyOperation(@NonNull IBinder clientId, int code, @NonNull AttributionSource attributionSource, boolean skipProxyOperation) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { - mPolicy.finishProxyOperation(code, attributionSource, + mPolicy.finishProxyOperation(clientId, code, attributionSource, skipProxyOperation, this::finishDelegateProxyOperationImpl); } else { - mPolicy.finishProxyOperation(code, attributionSource, + mPolicy.finishProxyOperation(clientId, code, attributionSource, skipProxyOperation, AppOpsService.this::finishProxyOperationImpl); } } else if (mCheckOpsDelegate != null) { - finishDelegateProxyOperationImpl(code, attributionSource, skipProxyOperation); + finishDelegateProxyOperationImpl(clientId, code, attributionSource, + skipProxyOperation); } else { - finishProxyOperationImpl(code, attributionSource, skipProxyOperation); + finishProxyOperationImpl(clientId, code, attributionSource, skipProxyOperation); } } - private Void finishDelegateProxyOperationImpl(int code, + private Void finishDelegateProxyOperationImpl(@NonNull IBinder clientId, int code, @NonNull AttributionSource attributionSource, boolean skipProxyOperation) { - mCheckOpsDelegate.finishProxyOperation(code, attributionSource, skipProxyOperation, - AppOpsService.this::finishProxyOperationImpl); + mCheckOpsDelegate.finishProxyOperation(clientId, code, attributionSource, + skipProxyOperation, AppOpsService.this::finishProxyOperationImpl); return null; } } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Mutable.java b/services/core/java/com/android/server/broadcastradio/hal2/Mutable.java index a9d80549f963..a6cf72c548c4 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/Mutable.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/Mutable.java @@ -34,13 +34,4 @@ final class Mutable<E> { public Mutable() { value = null; } - - /** - * Initialize value with specific value. - * - * @param value initial value. - */ - public Mutable(E value) { - this.value = value; - } } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Utils.java b/services/core/java/com/android/server/broadcastradio/hal2/Utils.java index f6e90ef4197c..188c25d37fc3 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/Utils.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/Utils.java @@ -25,7 +25,7 @@ enum FrequencyBand { AM_LW, AM_MW, AM_SW, -}; +} class Utils { diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java index 573bf19023fa..5646e1b9a9ef 100644 --- a/services/core/java/com/android/server/hdmi/HdmiUtils.java +++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java @@ -20,6 +20,8 @@ import static com.android.server.hdmi.Constants.ADDR_BACKUP_1; import static com.android.server.hdmi.Constants.ADDR_BACKUP_2; import static com.android.server.hdmi.Constants.ADDR_TV; +import static java.util.Map.entry; + import android.annotation.Nullable; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; @@ -45,7 +47,6 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -57,38 +58,34 @@ final class HdmiUtils { private static final String TAG = "HdmiUtils"; - private static final Map<Integer, List<Integer>> ADDRESS_TO_TYPE = - new HashMap<Integer, List<Integer>>() { - { - put(Constants.ADDR_TV, Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV)); - put(Constants.ADDR_RECORDER_1, - Lists.newArrayList(HdmiDeviceInfo.DEVICE_RECORDER)); - put(Constants.ADDR_RECORDER_2, - Lists.newArrayList(HdmiDeviceInfo.DEVICE_RECORDER)); - put(Constants.ADDR_TUNER_1, Lists.newArrayList(HdmiDeviceInfo.DEVICE_TUNER)); - put(Constants.ADDR_PLAYBACK_1, - Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK)); - put(Constants.ADDR_AUDIO_SYSTEM, - Lists.newArrayList(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)); - put(Constants.ADDR_TUNER_2, Lists.newArrayList(HdmiDeviceInfo.DEVICE_TUNER)); - put(Constants.ADDR_TUNER_3, Lists.newArrayList(HdmiDeviceInfo.DEVICE_TUNER)); - put(Constants.ADDR_PLAYBACK_2, - Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK)); - put(Constants.ADDR_RECORDER_3, - Lists.newArrayList(HdmiDeviceInfo.DEVICE_RECORDER)); - put(Constants.ADDR_TUNER_4, Lists.newArrayList(HdmiDeviceInfo.DEVICE_TUNER)); - put(Constants.ADDR_PLAYBACK_3, - Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK)); - put(Constants.ADDR_BACKUP_1, Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK, - HdmiDeviceInfo.DEVICE_RECORDER, HdmiDeviceInfo.DEVICE_TUNER, - HdmiDeviceInfo.DEVICE_VIDEO_PROCESSOR)); - put(Constants.ADDR_BACKUP_2, Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK, - HdmiDeviceInfo.DEVICE_RECORDER, HdmiDeviceInfo.DEVICE_TUNER, - HdmiDeviceInfo.DEVICE_VIDEO_PROCESSOR)); - put(Constants.ADDR_SPECIFIC_USE, Lists.newArrayList(ADDR_TV)); - put(Constants.ADDR_UNREGISTERED, Collections.emptyList()); - } - }; + private static final Map<Integer, List<Integer>> ADDRESS_TO_TYPE = Map.ofEntries( + entry(Constants.ADDR_TV, Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV)), + entry(Constants.ADDR_RECORDER_1, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_RECORDER)), + entry(Constants.ADDR_RECORDER_2, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_RECORDER)), + entry(Constants.ADDR_TUNER_1, Lists.newArrayList(HdmiDeviceInfo.DEVICE_TUNER)), + entry(Constants.ADDR_PLAYBACK_1, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK)), + entry(Constants.ADDR_AUDIO_SYSTEM, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)), + entry(Constants.ADDR_TUNER_2, Lists.newArrayList(HdmiDeviceInfo.DEVICE_TUNER)), + entry(Constants.ADDR_TUNER_3, Lists.newArrayList(HdmiDeviceInfo.DEVICE_TUNER)), + entry(Constants.ADDR_PLAYBACK_2, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK)), + entry(Constants.ADDR_RECORDER_3, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_RECORDER)), + entry(Constants.ADDR_TUNER_4, Lists.newArrayList(HdmiDeviceInfo.DEVICE_TUNER)), + entry(Constants.ADDR_PLAYBACK_3, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK)), + entry(Constants.ADDR_BACKUP_1, Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK, + HdmiDeviceInfo.DEVICE_RECORDER, HdmiDeviceInfo.DEVICE_TUNER, + HdmiDeviceInfo.DEVICE_VIDEO_PROCESSOR)), + entry(Constants.ADDR_BACKUP_2, Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK, + HdmiDeviceInfo.DEVICE_RECORDER, HdmiDeviceInfo.DEVICE_TUNER, + HdmiDeviceInfo.DEVICE_VIDEO_PROCESSOR)), + entry(Constants.ADDR_SPECIFIC_USE, Lists.newArrayList(ADDR_TV)), + entry(Constants.ADDR_UNREGISTERED, Collections.emptyList())); private static final String[] DEFAULT_NAMES = { "TV", diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index cb615a9729f6..8497dfb58ba6 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -1814,8 +1814,8 @@ public class InputManagerService extends IInputManager.Stub */ public boolean transferTouchFocus(@NonNull IBinder fromChannelToken, @NonNull IBinder toChannelToken) { - Objects.nonNull(fromChannelToken); - Objects.nonNull(toChannelToken); + Objects.requireNonNull(fromChannelToken); + Objects.requireNonNull(toChannelToken); return mNative.transferTouchFocus(fromChannelToken, toChannelToken, false /* isDragDrop */); } diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java index 4f6d0d472d26..e46b8c0c06b3 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java @@ -523,9 +523,9 @@ import java.util.concurrent.atomic.AtomicInteger; @Override public String toString() { StringBuilder sb = new StringBuilder(100); - TransactionRecord[] arr; + ContextHubServiceTransaction[] arr; synchronized (this) { - arr = mTransactionQueue.toArray(new TransactionRecord[0]); + arr = mTransactionQueue.toArray(new ContextHubServiceTransaction[0]); } for (int i = 0; i < arr.length; i++) { sb.append(i + ": " + arr[i] + "\n"); diff --git a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java index b8abd98456e4..77cd67304729 100644 --- a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java +++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java @@ -296,26 +296,24 @@ public class GnssConfiguration { Log.e(TAG, "Unable to set " + CONFIG_ES_EXTENSION_SEC + ": " + mEsExtensionSec); } - Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() { - { - put(CONFIG_SUPL_VER, GnssConfiguration::native_set_supl_version); - put(CONFIG_SUPL_MODE, GnssConfiguration::native_set_supl_mode); + Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>(); - if (isConfigSuplEsSupported(gnssConfigurationIfaceVersion)) { - put(CONFIG_SUPL_ES, GnssConfiguration::native_set_supl_es); - } + map.put(CONFIG_SUPL_VER, GnssConfiguration::native_set_supl_version); + map.put(CONFIG_SUPL_MODE, GnssConfiguration::native_set_supl_mode); - put(CONFIG_LPP_PROFILE, GnssConfiguration::native_set_lpp_profile); - put(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT, - GnssConfiguration::native_set_gnss_pos_protocol_select); - put(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL, - GnssConfiguration::native_set_emergency_supl_pdn); + if (isConfigSuplEsSupported(gnssConfigurationIfaceVersion)) { + map.put(CONFIG_SUPL_ES, GnssConfiguration::native_set_supl_es); + } - if (isConfigGpsLockSupported(gnssConfigurationIfaceVersion)) { - put(CONFIG_GPS_LOCK, GnssConfiguration::native_set_gps_lock); - } - } - }; + map.put(CONFIG_LPP_PROFILE, GnssConfiguration::native_set_lpp_profile); + map.put(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT, + GnssConfiguration::native_set_gnss_pos_protocol_select); + map.put(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL, + GnssConfiguration::native_set_emergency_supl_pdn); + + if (isConfigGpsLockSupported(gnssConfigurationIfaceVersion)) { + map.put(CONFIG_GPS_LOCK, GnssConfiguration::native_set_gps_lock); + } for (Entry<String, SetCarrierProperty> entry : map.entrySet()) { String propertyName = entry.getKey(); diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index bbbf4520b791..1bbcc839ccd1 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -852,7 +852,9 @@ public class PreferencesHelper implements RankingConfig { Objects.requireNonNull(pkg); Objects.requireNonNull(group); Objects.requireNonNull(group.getId()); - Objects.requireNonNull(!TextUtils.isEmpty(group.getName())); + if (TextUtils.isEmpty(group.getName())) { + throw new IllegalArgumentException("group.getName() can't be empty"); + } boolean needsDndChange = false; synchronized (mPackagePreferences) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); diff --git a/services/core/java/com/android/server/pm/PerPackageReadTimeouts.java b/services/core/java/com/android/server/pm/PerPackageReadTimeouts.java index 3b306a850b64..b310c62aafb4 100644 --- a/services/core/java/com/android/server/pm/PerPackageReadTimeouts.java +++ b/services/core/java/com/android/server/pm/PerPackageReadTimeouts.java @@ -16,7 +16,7 @@ package com.android.server.pm; -import android.annotation.NonNull;; +import android.annotation.NonNull; import android.text.TextUtils; import com.android.internal.util.HexDump; diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index ac487fa0b1b7..4a4a231f4fba 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -265,7 +265,7 @@ public class UserManagerService extends IUserManager.Stub { @VisibleForTesting static final int MAX_RECENTLY_REMOVED_IDS_SIZE = 100; - private static final int USER_VERSION = 10; + private static final int USER_VERSION = 11; private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms @@ -3355,6 +3355,7 @@ public class UserManagerService extends IUserManager.Stub { final int oldFlags = systemUserData.info.flags; final int newFlags; final String newUserType; + // TODO(b/256624031): Also handle FLAG_MAIN if (newHeadlessSystemUserMode) { newUserType = UserManager.USER_TYPE_SYSTEM_HEADLESS; newFlags = oldFlags & ~UserInfo.FLAG_FULL; @@ -3647,6 +3648,22 @@ public class UserManagerService extends IUserManager.Stub { userVersion = 10; } + if (userVersion < 11) { + // Add FLAG_MAIN + if (isHeadlessSystemUserMode()) { + final UserInfo earliestCreatedUser = getEarliestCreatedFullUser(); + earliestCreatedUser.flags |= UserInfo.FLAG_MAIN; + userIdsToWrite.add(earliestCreatedUser.id); + } else { + synchronized (mUsersLock) { + final UserData userData = mUsers.get(UserHandle.USER_SYSTEM); + userData.info.flags |= UserInfo.FLAG_MAIN; + userIdsToWrite.add(userData.info.id); + } + } + userVersion = 11; + } + // Reminder: If you add another upgrade, make sure to increment USER_VERSION too. // Done with userVersion changes, moving on to deal with userTypeVersion upgrades @@ -3776,6 +3793,21 @@ public class UserManagerService extends IUserManager.Stub { userInfo.profileBadge = getFreeProfileBadgeLU(userInfo.profileGroupId, userInfo.userType); } + private UserInfo getEarliestCreatedFullUser() { + final List<UserInfo> users = getUsersInternal(true, true, true); + UserInfo earliestUser = users.get(0); + long earliestCreationTime = earliestUser.creationTime; + for (int i = 0; i < users.size(); i++) { + final UserInfo info = users.get(i); + if (info.isFull() && info.isAdmin() && info.creationTime > 0 + && info.creationTime < earliestCreationTime) { + earliestCreationTime = info.creationTime; + earliestUser = info; + } + } + return earliestUser; + } + @GuardedBy({"mPackagesLock"}) private void fallbackToSingleUserLP() { int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java index 871420a92f44..8fb5773706c5 100644 --- a/services/core/java/com/android/server/pm/UserTypeFactory.java +++ b/services/core/java/com/android/server/pm/UserTypeFactory.java @@ -262,7 +262,8 @@ public final class UserTypeFactory { private static UserTypeDetails.Builder getDefaultTypeFullSystem() { return new UserTypeDetails.Builder() .setName(USER_TYPE_FULL_SYSTEM) - .setBaseType(FLAG_SYSTEM | FLAG_FULL); + .setBaseType(FLAG_SYSTEM | FLAG_FULL) + .setDefaultUserInfoPropertyFlags(UserInfo.FLAG_MAIN); } /** diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java index 5ba209d14933..9bca15519206 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java +++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java @@ -295,6 +295,7 @@ public final class DexoptUtils { * NOTE: Keep this in sync with the dexopt expectations! Right now that is either "PCL[path]" * for a PathClassLoader or "DLC[path]" for a DelegateLastClassLoader. */ + @SuppressWarnings("ReturnValueIgnored") /*package*/ static String encodeClassLoader(String classpath, String classLoaderName) { classpath.getClass(); // Throw NPE if classpath is null String classLoaderDexoptEncoding = classLoaderName; diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 28f86edaa724..83e17a5a9075 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -86,6 +86,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; /** @@ -165,6 +166,11 @@ final class DefaultPermissionGrantPolicy { COARSE_BACKGROUND_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION); } + private static final Set<String> FINE_LOCATION_PERMISSIONS = new ArraySet<>(); + static { + FINE_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION); + } + private static final Set<String> ACTIVITY_RECOGNITION_PERMISSIONS = new ArraySet<>(); static { ACTIVITY_RECOGNITION_PERMISSIONS.add(Manifest.permission.ACTIVITY_RECOGNITION); @@ -787,6 +793,8 @@ final class DefaultPermissionGrantPolicy { CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS, PHONE_PERMISSIONS, SMS_PERMISSIONS, COARSE_BACKGROUND_LOCATION_PERMISSIONS, NEARBY_DEVICES_PERMISSIONS, NOTIFICATION_PERMISSIONS); + revokeRuntimePermissions(pm, voiceInteractPackageName, FINE_LOCATION_PERMISSIONS, + false, userId); } } @@ -1932,7 +1940,7 @@ final class DefaultPermissionGrantPolicy { mPkgRequestingPerm, newRestrictionExcemptFlags, -1, mUser); } - if (newGranted != null && newGranted != mOriginalGranted) { + if (newGranted != null && !Objects.equals(newGranted, mOriginalGranted)) { if (newGranted) { NO_PM_CACHE.grantPermission(mPermission, mPkgRequestingPerm, mUser); } else { 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 5a638bbd5abd..9ec63fcf7125 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1101,7 +1101,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (resolvedPackageName == null) { return; } - appOpsManager.finishOp(accessorSource.getToken(), op, + appOpsManager.finishOp(attributionSourceState.token, op, accessorSource.getUid(), resolvedPackageName, accessorSource.getAttributionTag()); } else { @@ -1110,8 +1110,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (resolvedAttributionSource.getPackageName() == null) { return; } - appOpsManager.finishProxyOp(AppOpsManager.opToPublicName(op), - resolvedAttributionSource, skipCurrentFinish); + appOpsManager.finishProxyOp(attributionSourceState.token, + AppOpsManager.opToPublicName(op), resolvedAttributionSource, + skipCurrentFinish); } RegisteredAttribution registered = sRunningAttributionSources.remove(current.getToken()); @@ -1227,10 +1228,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { && next.getNext() == null); final boolean selfAccess = singleReceiverFromDatasource || next == null; - final int opMode = performOpTransaction(context, op, current, message, - forDataDelivery, /*startDataDelivery*/ false, skipCurrentChecks, - selfAccess, singleReceiverFromDatasource, AppOpsManager.OP_NONE, - AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_FLAGS_NONE, + final int opMode = performOpTransaction(context, attributionSource.getToken(), op, + current, message, forDataDelivery, /*startDataDelivery*/ false, + skipCurrentChecks, selfAccess, singleReceiverFromDatasource, + AppOpsManager.OP_NONE, AppOpsManager.ATTRIBUTION_FLAGS_NONE, + AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); switch (opMode) { @@ -1333,10 +1335,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { attributionSource, next, fromDatasource, startDataDelivery, selfAccess, isLinkTrusted) : ATTRIBUTION_FLAGS_NONE; - final int opMode = performOpTransaction(context, op, current, message, - forDataDelivery, startDataDelivery, skipCurrentChecks, selfAccess, - singleReceiverFromDatasource, attributedOp, proxyAttributionFlags, - proxiedAttributionFlags, attributionChainId); + final int opMode = performOpTransaction(context, attributionSource.getToken(), op, + current, message, forDataDelivery, startDataDelivery, skipCurrentChecks, + selfAccess, singleReceiverFromDatasource, attributedOp, + proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); switch (opMode) { case AppOpsManager.MODE_ERRORED: { @@ -1481,8 +1483,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { attributionSource, next, /*fromDatasource*/ false, startDataDelivery, selfAccess, isLinkTrusted) : ATTRIBUTION_FLAGS_NONE; - final int opMode = performOpTransaction(context, op, current, message, - forDataDelivery, startDataDelivery, skipCurrentChecks, selfAccess, + final int opMode = performOpTransaction(context, current.getToken(), op, current, + message, forDataDelivery, startDataDelivery, skipCurrentChecks, selfAccess, /*fromDatasource*/ false, AppOpsManager.OP_NONE, proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); @@ -1504,7 +1506,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @SuppressWarnings("ConstantConditions") - private static int performOpTransaction(@NonNull Context context, int op, + private static int performOpTransaction(@NonNull Context context, + @NonNull IBinder chainStartToken, int op, @NonNull AttributionSource attributionSource, @Nullable String message, boolean forDataDelivery, boolean startDataDelivery, boolean skipProxyOperation, boolean selfAccess, boolean singleReceiverFromDatasource, int attributedOp, @@ -1566,7 +1569,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (selfAccess) { try { startedOpResult = appOpsManager.startOpNoThrow( - resolvedAttributionSource.getToken(), startedOp, + chainStartToken, startedOp, resolvedAttributionSource.getUid(), resolvedAttributionSource.getPackageName(), /*startIfModeDefault*/ false, @@ -1577,14 +1580,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { + " platform defined runtime permission " + AppOpsManager.opToPermission(op) + " while not having " + Manifest.permission.UPDATE_APP_OPS_STATS); - startedOpResult = appOpsManager.startProxyOpNoThrow(attributedOp, - attributionSource, message, skipProxyOperation, + startedOpResult = appOpsManager.startProxyOpNoThrow(chainStartToken, + attributedOp, attributionSource, message, skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); } } else { try { - startedOpResult = appOpsManager.startProxyOpNoThrow(startedOp, - resolvedAttributionSource, message, skipProxyOperation, + startedOpResult = appOpsManager.startProxyOpNoThrow(chainStartToken, + startedOp, resolvedAttributionSource, message, skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags, attributionChainId); } catch (SecurityException e) { //TODO 195339480: remove diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java index a6d148c824c9..383249f41f39 100644 --- a/services/core/java/com/android/server/policy/AppOpsPolicy.java +++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java @@ -45,13 +45,11 @@ import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.function.DecFunction; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.QuintConsumer; import com.android.internal.util.function.QuintFunction; -import com.android.internal.util.function.TriFunction; import com.android.internal.util.function.UndecFunction; import com.android.server.LocalServices; @@ -257,14 +255,14 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat } @Override - public SyncNotedAppOp startProxyOperation(int code, + public SyncNotedAppOp startProxyOperation(@NonNull IBinder clientId, int code, @NonNull AttributionSource attributionSource, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags, int attributionChainId, - @NonNull DecFunction<Integer, AttributionSource, Boolean, Boolean, String, Boolean, - Boolean, Integer, Integer, Integer, SyncNotedAppOp> superImpl) { - return superImpl.apply(resolveDatasourceOp(code, attributionSource.getUid(), + @NonNull UndecFunction<IBinder, Integer, AttributionSource, Boolean, Boolean, String, + Boolean, Boolean, Integer, Integer, Integer, SyncNotedAppOp> superImpl) { + return superImpl.apply(clientId, resolveDatasourceOp(code, attributionSource.getUid(), attributionSource.getPackageName(), attributionSource.getAttributionTag()), attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation, proxyAttributionFlags, @@ -280,10 +278,10 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat } @Override - public void finishProxyOperation(int code, @NonNull AttributionSource attributionSource, - boolean skipProxyOperation, @NonNull TriFunction<Integer, AttributionSource, - Boolean, Void> superImpl) { - superImpl.apply(resolveDatasourceOp(code, attributionSource.getUid(), + public void finishProxyOperation(@NonNull IBinder clientId, int code, + @NonNull AttributionSource attributionSource, boolean skipProxyOperation, + @NonNull QuadFunction<IBinder, Integer, AttributionSource, Boolean, Void> superImpl) { + superImpl.apply(clientId, resolveDatasourceOp(code, attributionSource.getUid(), attributionSource.getPackageName(), attributionSource.getAttributionTag()), attributionSource, skipProxyOperation); } diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java index dbddb41b601c..2c8fd967ae8a 100644 --- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java +++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java @@ -1066,7 +1066,28 @@ public class TvInteractiveAppManagerService extends SystemService { } finally { Binder.restoreCallingIdentity(identity); } + } + @Override + public void notifyRecordingStopped(IBinder sessionToken, String recordingId, int userId) { + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId, + "notifyRecordingStopped"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, + resolvedUserId); + getSessionLocked(sessionState).notifyRecordingStopped(recordingId); + } catch (RemoteException | SessionNotFoundException e) { + Slogf.e(TAG, "error in notifyRecordingStopped", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index b8cd8d9f3d71..c875f4af9c8b 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1897,12 +1897,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - private static final HashMap<Integer, String> sWallpaperType = new HashMap<Integer, String>() { - { - put(FLAG_SYSTEM, RECORD_FILE); - put(FLAG_LOCK, RECORD_LOCK_FILE); - } - }; + private static final Map<Integer, String> sWallpaperType = Map.of( + FLAG_SYSTEM, RECORD_FILE, + FLAG_LOCK, RECORD_LOCK_FILE); private void errorCheck(int userID) { sWallpaperType.forEach((type, filename) -> { diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java index e0644b61772a..b735b3083cbf 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java +++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java @@ -442,11 +442,12 @@ class DisplayWindowSettings { mRemoveContentMode = other.mRemoveContentMode; changed = true; } - if (other.mShouldShowWithInsecureKeyguard != mShouldShowWithInsecureKeyguard) { + if (!Objects.equals( + other.mShouldShowWithInsecureKeyguard, mShouldShowWithInsecureKeyguard)) { mShouldShowWithInsecureKeyguard = other.mShouldShowWithInsecureKeyguard; changed = true; } - if (other.mShouldShowSystemDecors != mShouldShowSystemDecors) { + if (!Objects.equals(other.mShouldShowSystemDecors, mShouldShowSystemDecors)) { mShouldShowSystemDecors = other.mShouldShowSystemDecors; changed = true; } @@ -458,15 +459,15 @@ class DisplayWindowSettings { mFixedToUserRotation = other.mFixedToUserRotation; changed = true; } - if (other.mIgnoreOrientationRequest != mIgnoreOrientationRequest) { + if (!Objects.equals(other.mIgnoreOrientationRequest, mIgnoreOrientationRequest)) { mIgnoreOrientationRequest = other.mIgnoreOrientationRequest; changed = true; } - if (other.mIgnoreDisplayCutout != mIgnoreDisplayCutout) { + if (!Objects.equals(other.mIgnoreDisplayCutout, mIgnoreDisplayCutout)) { mIgnoreDisplayCutout = other.mIgnoreDisplayCutout; changed = true; } - if (other.mDontMoveToTop != mDontMoveToTop) { + if (!Objects.equals(other.mDontMoveToTop, mDontMoveToTop)) { mDontMoveToTop = other.mDontMoveToTop; changed = true; } @@ -522,14 +523,13 @@ class DisplayWindowSettings { mRemoveContentMode = delta.mRemoveContentMode; changed = true; } - if (delta.mShouldShowWithInsecureKeyguard != null - && delta.mShouldShowWithInsecureKeyguard - != mShouldShowWithInsecureKeyguard) { + if (delta.mShouldShowWithInsecureKeyguard != null && !Objects.equals( + delta.mShouldShowWithInsecureKeyguard, mShouldShowWithInsecureKeyguard)) { mShouldShowWithInsecureKeyguard = delta.mShouldShowWithInsecureKeyguard; changed = true; } - if (delta.mShouldShowSystemDecors != null - && delta.mShouldShowSystemDecors != mShouldShowSystemDecors) { + if (delta.mShouldShowSystemDecors != null && !Objects.equals( + delta.mShouldShowSystemDecors, mShouldShowSystemDecors)) { mShouldShowSystemDecors = delta.mShouldShowSystemDecors; changed = true; } @@ -543,18 +543,18 @@ class DisplayWindowSettings { mFixedToUserRotation = delta.mFixedToUserRotation; changed = true; } - if (delta.mIgnoreOrientationRequest != null - && delta.mIgnoreOrientationRequest != mIgnoreOrientationRequest) { + if (delta.mIgnoreOrientationRequest != null && !Objects.equals( + delta.mIgnoreOrientationRequest, mIgnoreOrientationRequest)) { mIgnoreOrientationRequest = delta.mIgnoreOrientationRequest; changed = true; } - if (delta.mIgnoreDisplayCutout != null - && delta.mIgnoreDisplayCutout != mIgnoreDisplayCutout) { + if (delta.mIgnoreDisplayCutout != null && !Objects.equals( + delta.mIgnoreDisplayCutout, mIgnoreDisplayCutout)) { mIgnoreDisplayCutout = delta.mIgnoreDisplayCutout; changed = true; } - if (delta.mDontMoveToTop != null - && delta.mDontMoveToTop != mDontMoveToTop) { + if (delta.mDontMoveToTop != null && !Objects.equals( + delta.mDontMoveToTop, mDontMoveToTop)) { mDontMoveToTop = delta.mDontMoveToTop; changed = true; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 3419207eb14f..df343db8b3bf 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -426,7 +426,7 @@ public class WindowManagerService extends IWindowManager.Stub * @see #ENABLE_SHELL_TRANSITIONS */ public static final boolean sEnableShellTransitions = - SystemProperties.getBoolean(ENABLE_SHELL_TRANSITIONS, true); + SystemProperties.getBoolean(ENABLE_SHELL_TRANSITIONS, false); /** * Allows a fullscreen windowing mode activity to launch in its desired orientation directly diff --git a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java index 6f2930c46b12..1b70d1d4a8b6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java +++ b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java @@ -21,7 +21,7 @@ import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; import static android.os.Process.myTid; import static android.os.Process.setThreadPriority; -import static com.android.server.LockGuard.INDEX_WINDOW;; +import static com.android.server.LockGuard.INDEX_WINDOW; import com.android.internal.annotations.GuardedBy; import com.android.server.AnimationThread; diff --git a/services/java/com/android/server/BootUserInitializer.java b/services/java/com/android/server/BootUserInitializer.java index 46e59a9f10dd..c3329795d4e2 100644 --- a/services/java/com/android/server/BootUserInitializer.java +++ b/services/java/com/android/server/BootUserInitializer.java @@ -83,9 +83,10 @@ final class BootUserInitializer { Slogf.d(TAG, "Creating initial user"); t.traceBegin("create-initial-user"); try { + int flags = UserInfo.FLAG_ADMIN | UserInfo.FLAG_MAIN; // TODO(b/204091126): proper name for user UserInfo newUser = um.createUserEvenWhenDisallowed("Real User", - UserManager.USER_TYPE_FULL_SECONDARY, UserInfo.FLAG_ADMIN, + UserManager.USER_TYPE_FULL_SECONDARY, flags, /* disallowedPackages= */ null, /* token= */ null); Slogf.i(TAG, "Created initial user: %s", newUser.toFullString()); initialUserId = newUser.id; diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java index eab3b770a94a..292320e498a3 100644 --- a/services/people/java/com/android/server/people/PeopleService.java +++ b/services/people/java/com/android/server/people/PeopleService.java @@ -53,6 +53,7 @@ import com.android.server.people.data.DataManager; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Consumer; /** @@ -372,7 +373,8 @@ public class PeopleService extends SystemService { @Override public boolean equals(Object o) { ListenerKey key = (ListenerKey) o; - return key.getPackageName().equals(mPackageName) && key.getUserId() == mUserId + return key.getPackageName().equals(mPackageName) + && Objects.equals(key.getUserId(), mUserId) && key.getShortcutId().equals(mShortcutId); } diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp index 73b1907c9f42..681bfcf68cc3 100644 --- a/services/tests/mockingservicestests/Android.bp +++ b/services/tests/mockingservicestests/Android.bp @@ -56,6 +56,7 @@ android_test { "service-jobscheduler", "service-permission.impl", "service-sdksandbox.impl", + "services.backup", "services.companion", "services.core", "services.devicepolicy", diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java index d78f6d83d0ab..24e5175ecbdc 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -1507,6 +1507,39 @@ public class GameManagerServiceTests { } @Test + public void testSwitchUser() { + mockManageUsersGranted(); + mockModifyGameModeGranted(); + + mockDeviceConfigBattery(); + final Context context = InstrumentationRegistry.getContext(); + GameManagerService gameManagerService = new GameManagerService(mMockContext, + mTestLooper.getLooper(), context.getFilesDir()); + startUser(gameManagerService, USER_ID_1); + startUser(gameManagerService, USER_ID_2); + gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1); + checkReportedModes(gameManagerService, GameManager.GAME_MODE_STANDARD, + GameManager.GAME_MODE_BATTERY); + assertEquals(gameManagerService.getGameMode(mPackageName, USER_ID_1), + GameManager.GAME_MODE_BATTERY); + + mockDeviceConfigAll(); + switchUser(gameManagerService, USER_ID_1, USER_ID_2); + assertEquals(gameManagerService.getGameMode(mPackageName, USER_ID_2), + GameManager.GAME_MODE_STANDARD); + checkReportedModes(gameManagerService, GameManager.GAME_MODE_STANDARD, + GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_PERFORMANCE); + gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_2); + gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1); + + switchUser(gameManagerService, USER_ID_2, USER_ID_1); + checkReportedModes(gameManagerService, GameManager.GAME_MODE_STANDARD, + GameManager.GAME_MODE_BATTERY, GameManager.GAME_MODE_PERFORMANCE); + gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_2); + gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1); + } + + @Test public void testUpdateResolutionScalingFactor() { mockModifyGameModeGranted(); mockDeviceConfigBattery(); diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/BackupAndRestoreFeatureFlagsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAndRestoreFeatureFlagsTest.java new file mode 100644 index 000000000000..f53599731e10 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAndRestoreFeatureFlagsTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.backup; + +import android.platform.test.annotations.Presubmit; +import android.provider.DeviceConfig; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.modules.utils.testing.TestableDeviceConfig; + +import static com.google.common.truth.Truth.assertThat; + + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@Presubmit +@RunWith(AndroidJUnit4.class) +public class BackupAndRestoreFeatureFlagsTest { + @Rule + public TestableDeviceConfig.TestableDeviceConfigRule + mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule(); + + @Test + public void getBackupTransportFutureTimeoutMillis_notSet_returnsDefault() { + assertThat( + BackupAndRestoreFeatureFlags.getBackupTransportFutureTimeoutMillis()).isEqualTo( + 600000); + } + + @Test + public void getBackupTransportFutureTimeoutMillis_set_returnsSetValue() { + DeviceConfig.setProperty("backup_and_restore", "backup_transport_future_timeout_millis", + "1234", false); + + assertThat( + BackupAndRestoreFeatureFlags.getBackupTransportFutureTimeoutMillis()).isEqualTo( + 1234); + } + + @Test + public void getBackupTransportCallbackTimeoutMillis_notSet_returnsDefault() { + assertThat( + BackupAndRestoreFeatureFlags.getBackupTransportCallbackTimeoutMillis()).isEqualTo( + 300000); + } + + @Test + public void getBackupTransportCallbackTimeoutMillis_set_returnsSetValue() { + DeviceConfig.setProperty("backup_and_restore", "backup_transport_callback_timeout_millis", + "5678", false); + + assertThat( + BackupAndRestoreFeatureFlags.getBackupTransportCallbackTimeoutMillis()).isEqualTo( + 5678); + } +} diff --git a/services/tests/servicestests/src/com/android/server/camera/CameraServiceProxyTest.java b/services/tests/servicestests/src/com/android/server/camera/CameraServiceProxyTest.java index ea746d1f4fd3..faad961510d6 100644 --- a/services/tests/servicestests/src/com/android/server/camera/CameraServiceProxyTest.java +++ b/services/tests/servicestests/src/com/android/server/camera/CameraServiceProxyTest.java @@ -30,7 +30,7 @@ import android.hardware.camera2.CameraMetadata; import android.view.Display; import android.view.Surface; -import java.util.HashMap; +import java.util.Map; @RunWith(JUnit4.class) public class CameraServiceProxyTest { @@ -75,24 +75,22 @@ public class CameraServiceProxyTest { /*ignoreResizableAndSdkCheck*/true)).isEqualTo( CameraMetadata.SCALER_ROTATE_AND_CROP_NONE); // Check rotation and lens facing combinations - HashMap<Integer, Integer> backFacingMap = new HashMap<Integer, Integer>() {{ - put(Surface.ROTATION_0, CameraMetadata.SCALER_ROTATE_AND_CROP_NONE); - put(Surface.ROTATION_90, CameraMetadata.SCALER_ROTATE_AND_CROP_90); - put(Surface.ROTATION_270, CameraMetadata.SCALER_ROTATE_AND_CROP_270); - put(Surface.ROTATION_180, CameraMetadata.SCALER_ROTATE_AND_CROP_180); - }}; + Map<Integer, Integer> backFacingMap = Map.of( + Surface.ROTATION_0, CameraMetadata.SCALER_ROTATE_AND_CROP_NONE, + Surface.ROTATION_90, CameraMetadata.SCALER_ROTATE_AND_CROP_90, + Surface.ROTATION_270, CameraMetadata.SCALER_ROTATE_AND_CROP_270, + Surface.ROTATION_180, CameraMetadata.SCALER_ROTATE_AND_CROP_180); taskInfo.isFixedOrientationPortrait = true; backFacingMap.forEach((key, value) -> { assertThat(CameraServiceProxy.getCropRotateScale(ctx, ctx.getPackageName(), taskInfo, key, CameraCharacteristics.LENS_FACING_BACK, /*ignoreResizableAndSdkCheck*/true)).isEqualTo(value); }); - HashMap<Integer, Integer> frontFacingMap = new HashMap<Integer, Integer>() {{ - put(Surface.ROTATION_0, CameraMetadata.SCALER_ROTATE_AND_CROP_NONE); - put(Surface.ROTATION_90, CameraMetadata.SCALER_ROTATE_AND_CROP_270); - put(Surface.ROTATION_270, CameraMetadata.SCALER_ROTATE_AND_CROP_90); - put(Surface.ROTATION_180, CameraMetadata.SCALER_ROTATE_AND_CROP_180); - }}; + Map<Integer, Integer> frontFacingMap = Map.of( + Surface.ROTATION_0, CameraMetadata.SCALER_ROTATE_AND_CROP_NONE, + Surface.ROTATION_90, CameraMetadata.SCALER_ROTATE_AND_CROP_270, + Surface.ROTATION_270, CameraMetadata.SCALER_ROTATE_AND_CROP_90, + Surface.ROTATION_180, CameraMetadata.SCALER_ROTATE_AND_CROP_180); frontFacingMap.forEach((key, value) -> { assertThat(CameraServiceProxy.getCropRotateScale(ctx, ctx.getPackageName(), taskInfo, key, CameraCharacteristics.LENS_FACING_FRONT, diff --git a/services/tests/servicestests/src/com/android/server/display/AmbientBrightnessStatsTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/AmbientBrightnessStatsTrackerTest.java index df672c9f248d..2c4fe536b75c 100644 --- a/services/tests/servicestests/src/com/android/server/display/AmbientBrightnessStatsTrackerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/AmbientBrightnessStatsTrackerTest.java @@ -424,7 +424,7 @@ public class AmbientBrightnessStatsTrackerTest { @Override public LocalDate getLocalDate() { - return LocalDate.from(mLocalDate); + return mLocalDate; } } diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java index 9092ec325946..0884b784ac73 100644 --- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java @@ -367,6 +367,7 @@ public class InputMethodSubtypeSwitchingControllerTest { assertFalse(item_en_us_allcaps.mIsSystemLocale); } + @SuppressWarnings("SelfComparison") @Test public void testImeSubtypeListComparator() throws Exception { final ComponentName imeX1 = new ComponentName("com.example.imeX", "Ime1"); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTestable.java index 1e855a9819ac..1eb4fa5439e6 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTestable.java @@ -58,4 +58,4 @@ public class PasswordSlotManagerTestable extends PasswordSlotManager { } catch (Exception e) { } } -}; +} diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 0f93598d0f72..b64b28137f80 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -2727,7 +2727,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testCreateChannel_addToGroup() { - NotificationChannelGroup group = new NotificationChannelGroup("group", ""); + NotificationChannelGroup group = new NotificationChannelGroup("group", "group"); mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true); NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false)); @@ -3177,8 +3177,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testGetNotificationChannelGroupWithChannels() throws Exception { - NotificationChannelGroup group = new NotificationChannelGroup("group", ""); - NotificationChannelGroup other = new NotificationChannelGroup("something else", ""); + NotificationChannelGroup group = new NotificationChannelGroup("group", "group"); + NotificationChannelGroup other = new NotificationChannelGroup("something else", "name"); mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true); mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, other, true); diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbVCInputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/UsbVCInputTerminal.java index df637950899b..7a41b50e26bd 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbVCInputTerminal.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbVCInputTerminal.java @@ -46,4 +46,4 @@ public final class UsbVCInputTerminal extends UsbVCInterface { // TODO Add reporting specific to this descriptor super.report(canvas); } -}; +} diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbVCOutputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/UsbVCOutputTerminal.java index 4aa8ca22cc4e..32275a60644c 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbVCOutputTerminal.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbVCOutputTerminal.java @@ -46,4 +46,4 @@ public final class UsbVCOutputTerminal extends UsbVCInterface { super.report(canvas); // TODO Add reporting specific to this descriptor } -}; +} diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbVCProcessingUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbVCProcessingUnit.java index 5ce842e82598..0692066e1dee 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbVCProcessingUnit.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbVCProcessingUnit.java @@ -47,4 +47,4 @@ public final class UsbVCProcessingUnit extends UsbVCInterface { super.report(canvas); // TODO Add reporting specific to this descriptor } -}; +} diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbVCSelectorUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbVCSelectorUnit.java index 8e9b0d886389..604dd66905da 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbVCSelectorUnit.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbVCSelectorUnit.java @@ -47,4 +47,4 @@ public final class UsbVCSelectorUnit extends UsbVCInterface { super.report(canvas); // TODO Add reporting specific to this descriptor } -}; +} diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index 0721c281f15c..3e49aedbb41e 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -1321,4 +1321,4 @@ final class HotwordDetectionConnection { private static final String OP_MESSAGE = "Providing hotword detection result to VoiceInteractionService"; -}; +} diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java index f8bc499e87aa..763024fac838 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java @@ -913,4 +913,4 @@ final class VoiceInteractionSessionConnection implements ServiceConnection, } } }; -}; +} diff --git a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java index 8b01cb3c4405..2787d83a99a3 100644 --- a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java +++ b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java @@ -199,7 +199,6 @@ public class EncodedStringValue implements Cloneable { */ @Override public Object clone() throws CloneNotSupportedException { - super.clone(); int len = mData.length; byte[] dstBytes = new byte[len]; System.arraycopy(mData, 0, dstBytes, 0, len); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 936fad51f095..f38b902f7531 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -8698,6 +8698,15 @@ public class CarrierConfigManager { public static final String KEY_VONR_ENABLED_BOOL = "vonr_enabled_bool"; /** + * Boolean indicating the default VoNR user preference setting. + * If true, the VoNR setting will be enabled. If false, it will be disabled initially. + * + * Enabled by default. + * + */ + public static final String KEY_VONR_ON_BY_DEFAULT_BOOL = "vonr_on_by_default_bool"; + + /** * Determine whether unthrottle data retry when tracking area code (TAC/LAC) from cell changes * * @hide @@ -9520,6 +9529,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false); sDefaults.putBoolean(KEY_VONR_SETTING_VISIBILITY_BOOL, true); sDefaults.putBoolean(KEY_VONR_ENABLED_BOOL, false); + sDefaults.putBoolean(KEY_VONR_ON_BY_DEFAULT_BOOL, true); sDefaults.putIntArray(KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY, new int[] {}); sDefaults.putLong(KEY_PREMIUM_CAPABILITY_NOTIFICATION_DISPLAY_TIMEOUT_MILLIS_LONG, TimeUnit.MINUTES.toMillis(30)); diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java index 23835a7732cf..b83b400cb811 100644 --- a/telephony/java/android/telephony/DataFailCause.java +++ b/telephony/java/android/telephony/DataFailCause.java @@ -1620,29 +1620,26 @@ public final class DataFailCause { // If we are not able to find the configuration from carrier config, use the default // ones. if (permanentFailureSet == null) { - permanentFailureSet = new HashSet<Integer>() { - { - add(OPERATOR_BARRED); - add(MISSING_UNKNOWN_APN); - add(UNKNOWN_PDP_ADDRESS_TYPE); - add(USER_AUTHENTICATION); - add(ACTIVATION_REJECT_GGSN); - add(SERVICE_OPTION_NOT_SUPPORTED); - add(SERVICE_OPTION_NOT_SUBSCRIBED); - add(NSAPI_IN_USE); - add(ONLY_IPV4_ALLOWED); - add(ONLY_IPV6_ALLOWED); - add(PROTOCOL_ERRORS); - add(RADIO_POWER_OFF); - add(TETHERED_CALL_ACTIVE); - add(RADIO_NOT_AVAILABLE); - add(UNACCEPTABLE_NETWORK_PARAMETER); - add(SIGNAL_LOST); - add(DUPLICATE_CID); - add(MATCH_ALL_RULE_NOT_ALLOWED); - add(ALL_MATCHING_RULES_FAILED); - } - }; + permanentFailureSet = new HashSet<Integer>(); + permanentFailureSet.add(OPERATOR_BARRED); + permanentFailureSet.add(MISSING_UNKNOWN_APN); + permanentFailureSet.add(UNKNOWN_PDP_ADDRESS_TYPE); + permanentFailureSet.add(USER_AUTHENTICATION); + permanentFailureSet.add(ACTIVATION_REJECT_GGSN); + permanentFailureSet.add(SERVICE_OPTION_NOT_SUPPORTED); + permanentFailureSet.add(SERVICE_OPTION_NOT_SUBSCRIBED); + permanentFailureSet.add(NSAPI_IN_USE); + permanentFailureSet.add(ONLY_IPV4_ALLOWED); + permanentFailureSet.add(ONLY_IPV6_ALLOWED); + permanentFailureSet.add(PROTOCOL_ERRORS); + permanentFailureSet.add(RADIO_POWER_OFF); + permanentFailureSet.add(TETHERED_CALL_ACTIVE); + permanentFailureSet.add(RADIO_NOT_AVAILABLE); + permanentFailureSet.add(UNACCEPTABLE_NETWORK_PARAMETER); + permanentFailureSet.add(SIGNAL_LOST); + permanentFailureSet.add(DUPLICATE_CID); + permanentFailureSet.add(MATCH_ALL_RULE_NOT_ALLOWED); + permanentFailureSet.add(ALL_MATCHING_RULES_FAILED); } permanentFailureSet.add(NO_RETRY_FAILURE); diff --git a/telephony/java/android/telephony/data/QosBearerFilter.java b/telephony/java/android/telephony/data/QosBearerFilter.java index 0ab7b61bd73d..a0d9c1bdf1ed 100644 --- a/telephony/java/android/telephony/data/QosBearerFilter.java +++ b/telephony/java/android/telephony/data/QosBearerFilter.java @@ -130,6 +130,10 @@ public final class QosBearerFilter implements Parcelable { return precedence; } + public int getProtocol() { + return protocol; + } + public static class PortRange implements Parcelable { int start; int end; diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index a3cbb4a436bc..33c86d8299a0 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -50,7 +50,6 @@ import com.android.internal.telephony.util.TelephonyUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.CancellationException; @@ -179,10 +178,9 @@ public class ImsService extends Service { * Used for logging purposes, see {@link #getCapabilitiesString(long)} * @hide */ - private static final Map<Long, String> CAPABILITIES_LOG_MAP = new HashMap<Long, String>() {{ - put(CAPABILITY_EMERGENCY_OVER_MMTEL, "EMERGENCY_OVER_MMTEL"); - put(CAPABILITY_SIP_DELEGATE_CREATION, "SIP_DELEGATE_CREATION"); - }}; + private static final Map<Long, String> CAPABILITIES_LOG_MAP = Map.of( + CAPABILITY_EMERGENCY_OVER_MMTEL, "EMERGENCY_OVER_MMTEL", + CAPABILITY_SIP_DELEGATE_CREATION, "SIP_DELEGATE_CREATION"); /** * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService. diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java index 090d4136872e..9996b868afc7 100644 --- a/telephony/java/android/telephony/ims/RegistrationManager.java +++ b/telephony/java/android/telephony/ims/RegistrationManager.java @@ -78,24 +78,22 @@ public interface RegistrationManager { /**@hide*/ // Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN // and WWAN are more accurate constants. - Map<Integer, Integer> IMS_REG_TO_ACCESS_TYPE_MAP = - new HashMap<Integer, Integer>() {{ - // Map NONE to -1 to make sure that we handle the REGISTRATION_TECH_NONE - // case, since it is defined. - put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, - AccessNetworkConstants.TRANSPORT_TYPE_INVALID); - put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - put(ImsRegistrationImplBase.REGISTRATION_TECH_NR, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - /* As the cross sim will be using ePDG tunnel over internet, it behaves - like IWLAN in most cases. Hence setting the access type as IWLAN - */ - put(ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - }}; + Map<Integer, Integer> IMS_REG_TO_ACCESS_TYPE_MAP = Map.of( + // Map NONE to -1 to make sure that we handle the REGISTRATION_TECH_NONE + // case, since it is defined. + ImsRegistrationImplBase.REGISTRATION_TECH_NONE, + AccessNetworkConstants.TRANSPORT_TYPE_INVALID, + ImsRegistrationImplBase.REGISTRATION_TECH_LTE, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + ImsRegistrationImplBase.REGISTRATION_TECH_NR, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, + /* As the cross sim will be using ePDG tunnel over internet, it behaves + like IWLAN in most cases. Hence setting the access type as IWLAN + */ + ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); /** @hide */ @NonNull diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index a42327b8a1a9..174675fcde4c 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -34,7 +34,6 @@ import com.android.internal.telephony.util.RemoteCallbackListExt; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.HashMap; import java.util.Map; /** @@ -85,11 +84,10 @@ public abstract class ImsFeature { * Used for logging purposes. * @hide */ - public static final Map<Integer, String> FEATURE_LOG_MAP = new HashMap<Integer, String>() {{ - put(FEATURE_EMERGENCY_MMTEL, "EMERGENCY_MMTEL"); - put(FEATURE_MMTEL, "MMTEL"); - put(FEATURE_RCS, "RCS"); - }}; + public static final Map<Integer, String> FEATURE_LOG_MAP = Map.of( + FEATURE_EMERGENCY_MMTEL, "EMERGENCY_MMTEL", + FEATURE_MMTEL, "MMTEL", + FEATURE_RCS, "RCS"); /** * Integer values defining IMS features that are supported in ImsFeature. @@ -145,11 +143,10 @@ public abstract class ImsFeature { * Used for logging purposes. * @hide */ - public static final Map<Integer, String> STATE_LOG_MAP = new HashMap<Integer, String>() {{ - put(STATE_UNAVAILABLE, "UNAVAILABLE"); - put(STATE_INITIALIZING, "INITIALIZING"); - put(STATE_READY, "READY"); - }}; + public static final Map<Integer, String> STATE_LOG_MAP = Map.of( + STATE_UNAVAILABLE, "UNAVAILABLE", + STATE_INITIALIZING, "INITIALIZING", + STATE_READY, "READY"); /** * Integer values defining the result codes that should be returned from diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java index 0f4e122d147a..4bcf5a4e30d5 100644 --- a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java +++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java @@ -16,14 +16,16 @@ package com.android.test.hwuicompare; -import java.util.LinkedHashMap; -import java.util.Map.Entry; +import static java.util.Map.entry; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.util.Log; +import java.util.Map; +import java.util.Map.Entry; + public abstract class DisplayModifier { // automated tests ignore any combination of operations that don't together return TOTAL_MASK @@ -76,41 +78,36 @@ public abstract class DisplayModifier { }; @SuppressWarnings("serial") - private static final LinkedHashMap<String, LinkedHashMap<String, DisplayModifier>> gMaps = new LinkedHashMap<String, LinkedHashMap<String, DisplayModifier>>() { - { - put("aa", new LinkedHashMap<String, DisplayModifier>() { - { - put("true", new DisplayModifier() { + private static final Map<String, Map<String, DisplayModifier>> gMaps = Map.of( + "aa", Map.of( + "true", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setAntiAlias(true); } - }); - put("false", new DisplayModifier() { + }, + "false", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setAntiAlias(false); } - }); - } - }); - put("style", new LinkedHashMap<String, DisplayModifier>() { - { - put("fill", new DisplayModifier() { + }), + "style", Map.of( + "fill", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStyle(Paint.Style.FILL); } - }); - put("stroke", new DisplayModifier() { + }, + "stroke", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStyle(Paint.Style.STROKE); } @Override protected int mask() { return SWEEP_STROKE_WIDTH_BIT; } - }); - put("fillAndStroke", new DisplayModifier() { + }, + "fillAndStroke", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStyle(Paint.Style.FILL_AND_STROKE); @@ -118,131 +115,118 @@ public abstract class DisplayModifier { @Override protected int mask() { return SWEEP_STROKE_WIDTH_BIT; } - }); - } - }); - put("strokeWidth", new LinkedHashMap<String, DisplayModifier>() { - { - put("hair", new DisplayModifier() { + }), + "strokeWidth", Map.of( + "hair", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStrokeWidth(0); } @Override protected int mask() { return SWEEP_STROKE_WIDTH_BIT; } - }); - put("0.3", new DisplayModifier() { + }, + "0.3", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStrokeWidth(0.3f); } - }); - put("1", new DisplayModifier() { + }, + "1", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStrokeWidth(1); } - }); - put("5", new DisplayModifier() { + }, + "5", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStrokeWidth(5); } - }); - put("30", new DisplayModifier() { + }, + "30", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStrokeWidth(30); } - }); - } - }); - put("strokeCap", new LinkedHashMap<String, DisplayModifier>() { - { - put("butt", new DisplayModifier() { + }), + "strokeCap", Map.of( + "butt", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStrokeCap(Paint.Cap.BUTT); } @Override protected int mask() { return SWEEP_STROKE_CAP_BIT; } - }); - put("round", new DisplayModifier() { + }, + "round", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStrokeCap(Paint.Cap.ROUND); } - }); - put("square", new DisplayModifier() { + }, + "square", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStrokeCap(Paint.Cap.SQUARE); } - }); - } - }); - put("strokeJoin", new LinkedHashMap<String, DisplayModifier>() { - { - put("bevel", new DisplayModifier() { + }), + "strokeJoin", Map.of( + "bevel", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStrokeJoin(Paint.Join.BEVEL); } @Override protected int mask() { return SWEEP_STROKE_JOIN_BIT; } - }); - put("round", new DisplayModifier() { + }, + "round", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStrokeJoin(Paint.Join.ROUND); } - }); - put("miter", new DisplayModifier() { + }, + "miter", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setStrokeJoin(Paint.Join.MITER); } - }); + }), // TODO: add miter0, miter1 etc to test miter distances - } - }); - - put("transform", new LinkedHashMap<String, DisplayModifier>() { - { - put("noTransform", new DisplayModifier() { + "transform", Map.of( + "noTransform", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) {} @Override protected int mask() { return SWEEP_TRANSFORM_BIT; }; - }); - put("rotate5", new DisplayModifier() { + }, + "rotate5", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.rotate(5); } - }); - put("rotate45", new DisplayModifier() { + }, + "rotate45", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.rotate(45); } - }); - put("rotate90", new DisplayModifier() { + }, + "rotate90", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.rotate(90); canvas.translate(0, -200); } - }); - put("scale2x2", new DisplayModifier() { + }, + "scale2x2", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.scale(2, 2); } @Override protected int mask() { return SWEEP_TRANSFORM_BIT; }; - }); - put("rot20scl1x4", new DisplayModifier() { + }, + "rot20scl1x4", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.rotate(20); @@ -250,180 +234,167 @@ public abstract class DisplayModifier { } @Override protected int mask() { return SWEEP_TRANSFORM_BIT; }; - }); - } - }); - - put("shader", new LinkedHashMap<String, DisplayModifier>() { - { - put("noShader", new DisplayModifier() { + }), + "shader", Map.ofEntries( + entry("noShader", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) {} @Override protected int mask() { return SWEEP_SHADER_BIT; }; - }); - put("repeatShader", new DisplayModifier() { + }), + entry("repeatShader", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setShader(ResourceModifiers.instance().mRepeatShader); } @Override protected int mask() { return SWEEP_SHADER_BIT; }; - }); - put("translatedShader", new DisplayModifier() { + }), + entry("translatedShader", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setShader(ResourceModifiers.instance().mTranslatedShader); } - }); - put("scaledShader", new DisplayModifier() { + }), + entry("scaledShader", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setShader(ResourceModifiers.instance().mScaledShader); } - }); - put("horGradient", new DisplayModifier() { + }), + entry("horGradient", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setShader(ResourceModifiers.instance().mHorGradient); } - }); - put("diagGradient", new DisplayModifier() { + }), + entry("diagGradient", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setShader(ResourceModifiers.instance().mDiagGradient); } @Override protected int mask() { return SWEEP_SHADER_BIT; }; - }); - put("vertGradient", new DisplayModifier() { + }), + entry("vertGradient", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setShader(ResourceModifiers.instance().mVertGradient); } - }); - put("radGradient", new DisplayModifier() { + }), + entry("radGradient", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setShader(ResourceModifiers.instance().mRadGradient); } - }); - put("sweepGradient", new DisplayModifier() { + }), + entry("sweepGradient", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setShader(ResourceModifiers.instance().mSweepGradient); } - }); - put("composeShader", new DisplayModifier() { + }), + entry("composeShader", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setShader(ResourceModifiers.instance().mComposeShader); } - }); - put("bad composeShader", new DisplayModifier() { + }), + entry("bad composeShader", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setShader(ResourceModifiers.instance().mBadComposeShader); } - }); - put("bad composeShader 2", new DisplayModifier() { + }), + entry("bad composeShader 2", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setShader(ResourceModifiers.instance().mAnotherBadComposeShader); } - }); - } - }); - - // FINAL MAP: DOES ACTUAL DRAWING - put("drawing", new LinkedHashMap<String, DisplayModifier>() { - { - put("roundRect", new DisplayModifier() { + })), + "drawing", Map.ofEntries( + entry("roundRect", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.drawRoundRect(gRect, 20, 20, paint); } - }); - put("rect", new DisplayModifier() { + }), + entry("rect", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.drawRect(gRect, paint); } @Override protected int mask() { return SWEEP_SHADER_BIT | SWEEP_STROKE_CAP_BIT; }; - }); - put("circle", new DisplayModifier() { + }), + entry("circle", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.drawCircle(100, 100, 75, paint); } - }); - put("oval", new DisplayModifier() { + }), + entry("oval", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.drawOval(gRect, paint); } - }); - put("lines", new DisplayModifier() { + }), + entry("lines", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.drawLines(gLinePts, paint); } @Override protected int mask() { return SWEEP_STROKE_CAP_BIT; }; - }); - put("plusPoints", new DisplayModifier() { + }), + entry("plusPoints", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.drawPoints(gPts, paint); } - }); - put("text", new DisplayModifier() { + }), + entry("text", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setTextSize(36); canvas.drawText("TEXTTEST", 0, 50, paint); } - }); - put("shadowtext", new DisplayModifier() { + }), + entry("shadowtext", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { paint.setTextSize(36); paint.setShadowLayer(3.0f, 0.0f, 3.0f, 0xffff00ff); canvas.drawText("TEXTTEST", 0, 50, paint); } - }); - put("bitmapMesh", new DisplayModifier() { + }), + entry("bitmapMesh", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.drawBitmapMesh(ResourceModifiers.instance().mBitmap, 3, 3, ResourceModifiers.instance().mBitmapVertices, 0, null, 0, null); } - }); - put("arc", new DisplayModifier() { + }), + entry("arc", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.drawArc(gRect, 260, 285, false, paint); } @Override protected int mask() { return SWEEP_STROKE_CAP_BIT; }; - }); - put("arcFromCenter", new DisplayModifier() { + }), + entry("arcFromCenter", new DisplayModifier() { @Override public void modifyDrawing(Paint paint, Canvas canvas) { canvas.drawArc(gRect, 260, 285, true, paint); } @Override protected int mask() { return SWEEP_STROKE_JOIN_BIT; }; - }); - } - }); + }))); // WARNING: DON'T PUT MORE MAPS BELOW THIS - } - }; - private static LinkedHashMap<String, DisplayModifier> getMapAtIndex(int index) { - for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { + private static Map<String, DisplayModifier> getMapAtIndex(int index) { + for (Map<String, DisplayModifier> map : gMaps.values()) { if (index == 0) { return map; } @@ -439,7 +410,7 @@ public abstract class DisplayModifier { private static boolean stepInternal(boolean forward) { int modifierMapIndex = gMaps.size() - 1; while (modifierMapIndex >= 0) { - LinkedHashMap<String, DisplayModifier> map = getMapAtIndex(modifierMapIndex); + Map<String, DisplayModifier> map = getMapAtIndex(modifierMapIndex); mIndices[modifierMapIndex] += (forward ? 1 : -1); if (mIndices[modifierMapIndex] >= 0 && mIndices[modifierMapIndex] < map.size()) { @@ -471,7 +442,7 @@ public abstract class DisplayModifier { private static boolean checkModificationStateMask() { int operatorMask = 0x0; int mapIndex = 0; - for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { + for (Map<String, DisplayModifier> map : gMaps.values()) { int displayModifierIndex = mIndices[mapIndex]; for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) { if (displayModifierIndex == 0) { @@ -488,7 +459,7 @@ public abstract class DisplayModifier { public static void apply(Paint paint, Canvas canvas) { int mapIndex = 0; - for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { + for (Map<String, DisplayModifier> map : gMaps.values()) { int displayModifierIndex = mIndices[mapIndex]; for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) { if (displayModifierIndex == 0) { @@ -510,7 +481,7 @@ public abstract class DisplayModifier { String[][] keys = new String[gMaps.size()][]; int i = 0; - for (LinkedHashMap<String, DisplayModifier> map : gMaps.values()) { + for (Map<String, DisplayModifier> map : gMaps.values()) { keys[i] = new String[map.size()]; int j = 0; for (String key : map.keySet()) { diff --git a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java index 2ad0da98c409..8b9c02049351 100644 --- a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java +++ b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java @@ -58,7 +58,7 @@ public class ViewDumpParser { Object hash = getProperty(props, "__hash__"); if (name instanceof String && hash instanceof Integer) { - return String.format(Locale.US, "%s@%x", name, hash); + return String.format(Locale.US, "%s@%x", name, (Integer) hash); } else { return null; } diff --git a/tests/JankBench/app/src/main/java/com/android/benchmark/app/HomeActivity.java b/tests/JankBench/app/src/main/java/com/android/benchmark/app/HomeActivity.java index 4de51fb57308..43dc9de6c90a 100644 --- a/tests/JankBench/app/src/main/java/com/android/benchmark/app/HomeActivity.java +++ b/tests/JankBench/app/src/main/java/com/android/benchmark/app/HomeActivity.java @@ -140,9 +140,9 @@ public class HomeActivity extends AppCompatActivity implements Button.OnClickLis handleNextBenchmark(); } + @SuppressWarnings("MissingSuperCall") // TODO: Fix me @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - } private void handleNextBenchmark() { diff --git a/tests/JankBench/app/src/main/java/com/android/benchmark/app/RunLocalBenchmarksActivity.java b/tests/JankBench/app/src/main/java/com/android/benchmark/app/RunLocalBenchmarksActivity.java index c16efbda1830..d015a5695ec0 100644 --- a/tests/JankBench/app/src/main/java/com/android/benchmark/app/RunLocalBenchmarksActivity.java +++ b/tests/JankBench/app/src/main/java/com/android/benchmark/app/RunLocalBenchmarksActivity.java @@ -367,6 +367,7 @@ public class RunLocalBenchmarksActivity extends AppCompatActivity { } } + @SuppressWarnings("MissingSuperCall") // TODO: Fix me @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { diff --git a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java index 8afe8411a790..17fa210a1db6 100644 --- a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java +++ b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java @@ -295,8 +295,8 @@ public class MirrorSurfaceActivity extends Activity implements View.OnClickListe private void updateMirror(Rect displayFrame, float scale) { if (displayFrame.isEmpty()) { Rect bounds = mWindowBounds; - int defaultCropW = Math.round(bounds.width() / 2); - int defaultCropH = Math.round(bounds.height() / 2); + int defaultCropW = bounds.width() / 2; + int defaultCropH = bounds.height() / 2; displayFrame.set(0, 0, defaultCropW, defaultCropH); } diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java index 241206d8919b..65b7549f22d1 100644 --- a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java +++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java @@ -24,18 +24,14 @@ public class MainActivity extends Activity implements OnItemClickListener { static final String KEY_NAME = "name"; static final String KEY_CLASS = "clazz"; - static Map<String,?> make(String name) { - Map<String,Object> ret = new HashMap<String,Object>(); - ret.put(KEY_NAME, name); - return ret; - } - - @SuppressWarnings("serial") - static final ArrayList<Map<String,?>> SAMPLES = new ArrayList<Map<String,?>>() {{ + static final ArrayList<Map<String, ?>> SAMPLES = new ArrayList<>(); + static { for (int i = 1; i < 25; i++) { - add(make("List Item: " + i)); + Map<String, Object> sample = new HashMap<String, Object>(); + sample.put(KEY_NAME, "List Item: " + i); + SAMPLES.add(sample); } - }}; + } Handler mHandler = new Handler(); diff --git a/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java index c11b0f3acf79..f85fb0f267d5 100644 --- a/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java +++ b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java @@ -30,6 +30,7 @@ public class CrashyApp extends Activity { setContentView(tv); } + @SuppressWarnings("ReturnValueIgnored") @Override public void onResume() { ((String) null).length(); diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index f924b2e9b932..ad068308d481 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -637,8 +637,7 @@ public class VcnManagementServiceTest { final BroadcastReceiver receiver = getPackageChangeReceiver(); verify(mMockContext).registerReceiver(any(), argThat(filter -> { - return filter.hasAction(Intent.ACTION_PACKAGE_REMOVED) - && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED); + return filter.hasAction(Intent.ACTION_PACKAGE_REMOVED); }), any(), any()); receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_REMOVED)); diff --git a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java index a750696628f9..50126226eb94 100644 --- a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java +++ b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java @@ -117,13 +117,12 @@ public class WifiNl80211ManagerTest { private static final byte[] TEST_PSK = new byte[]{'T', 'e', 's', 't'}; - private static final Set<Integer> SCAN_FREQ_SET = - new HashSet<Integer>() {{ - add(2410); - add(2450); - add(5050); - add(5200); - }}; + private static final Set<Integer> SCAN_FREQ_SET = Set.of( + 2410, + 2450, + 5050, + 5200); + private static final String TEST_QUOTED_SSID_1 = "\"testSsid1\""; private static final String TEST_QUOTED_SSID_2 = "\"testSsid2\""; private static final int[] TEST_FREQUENCIES_1 = {}; @@ -131,13 +130,11 @@ public class WifiNl80211ManagerTest { private static final MacAddress TEST_RAW_MAC_BYTES = MacAddress.fromBytes( new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}); - private static final List<byte[]> SCAN_HIDDEN_NETWORK_SSID_LIST = - new ArrayList<byte[]>() {{ - add(LocalNativeUtil.byteArrayFromArrayList( - LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_1))); - add(LocalNativeUtil.byteArrayFromArrayList( - LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2))); - }}; + private static final List<byte[]> SCAN_HIDDEN_NETWORK_SSID_LIST = List.of( + LocalNativeUtil.byteArrayFromArrayList( + LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_1)), + LocalNativeUtil.byteArrayFromArrayList( + LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2))); private static final PnoSettings TEST_PNO_SETTINGS = new PnoSettings(); static { |