Merge "Updated AggregatedMobileDataStatsPuller" into main
diff --git a/boot/Android.bp b/boot/Android.bp
index cdfa7c80..f60bb9e 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -31,6 +31,7 @@
"car_bootclasspath_fragment",
"nfc_apex_bootclasspath_fragment",
"release_crashrecovery_module",
+ "release_package_profiling_module",
],
properties: [
"fragments",
@@ -122,10 +123,6 @@
module: "com.android.permission-bootclasspath-fragment",
},
{
- apex: "com.android.profiling",
- module: "com.android.profiling-bootclasspath-fragment",
- },
- {
apex: "com.android.scheduling",
module: "com.android.scheduling-bootclasspath-fragment",
},
@@ -179,6 +176,15 @@
},
],
},
+ release_package_profiling_module: {
+ fragments: [
+ // only used if profiling is enabled.
+ {
+ apex: "com.android.profiling",
+ module: "com.android.profiling-bootclasspath-fragment",
+ },
+ ],
+ },
},
// Additional information needed by hidden api processing.
diff --git a/core/api/current.txt b/core/api/current.txt
index d9c82b1..bc89f12 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -203,7 +203,7 @@
field public static final String MANAGE_DEVICE_POLICY_SYSTEM_APPS = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_APPS";
field public static final String MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS";
field public static final String MANAGE_DEVICE_POLICY_SYSTEM_UPDATES = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES";
- field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String MANAGE_DEVICE_POLICY_THREAD_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK";
+ field @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") public static final String MANAGE_DEVICE_POLICY_THREAD_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK";
field public static final String MANAGE_DEVICE_POLICY_TIME = "android.permission.MANAGE_DEVICE_POLICY_TIME";
field public static final String MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING = "android.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING";
field public static final String MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER = "android.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER";
@@ -13218,7 +13218,7 @@
field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio.access";
field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription";
field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television";
- field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
+ field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
@@ -34086,7 +34086,7 @@
field @FlaggedApi("android.app.admin.flags.esim_management_enabled") public static final String DISALLOW_SIM_GLOBALLY = "no_sim_globally";
field public static final String DISALLOW_SMS = "no_sms";
field public static final String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs";
- field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
+ field @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
field public static final String DISALLOW_ULTRA_WIDEBAND_RADIO = "no_ultra_wideband_radio";
field public static final String DISALLOW_UNIFIED_PASSWORD = "no_unified_password";
field public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b2db7c1..2fec0ad 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -388,7 +388,7 @@
field public static final String SYSTEM_APPLICATION_OVERLAY = "android.permission.SYSTEM_APPLICATION_OVERLAY";
field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA";
field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
- field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED";
+ field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED";
field public static final String TIS_EXTENSION_INTERFACE = "android.permission.TIS_EXTENSION_INTERFACE";
field public static final String TOGGLE_AUTOMOTIVE_PROJECTION = "android.permission.TOGGLE_AUTOMOTIVE_PROJECTION";
field public static final String TRIGGER_LOST_MODE = "android.permission.TRIGGER_LOST_MODE";
@@ -3787,7 +3787,7 @@
field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
field public static final String TETHERING_SERVICE = "tethering";
- field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network";
+ field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network";
field public static final String TIME_MANAGER_SERVICE = "time_manager";
field public static final String TRANSLATION_MANAGER_SERVICE = "translation";
field public static final String UI_TRANSLATION_SERVICE = "ui_translation";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index cdf232c..b8c32a4 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -251,6 +251,7 @@
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
method public static int getNumOps();
method public boolean isOperationActive(int, int, String);
+ method public int noteOpNoThrow(int, @NonNull android.content.AttributionSource, @Nullable String);
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void offsetHistory(long);
method public static String opToPermission(int);
method public static int permissionToOpCode(String);
@@ -3966,6 +3967,7 @@
}
public final class InputMethodInfo implements android.os.Parcelable {
+ ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, @NonNull String);
ctor @FlaggedApi("android.view.inputmethod.connectionless_handwriting") public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, boolean, @NonNull String);
ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
field public static final int COMPONENT_NAME_MAX_LENGTH = 1000; // 0x3e8
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 39900a0..2afc78c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7800,7 +7800,7 @@
}
final List<AppOpsManager.PackageOps> result;
try {
- result = mService.getPackagesForOpsForDevice(opCodes, persistentDeviceId);
+ result = mService.getPackagesForOpsForDevice(opCodes, persistentDeviceId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8272,14 +8272,24 @@
cb = new IAppOpsCallback.Stub() {
public void opChanged(int op, int uid, String packageName,
String persistentDeviceId) {
- if (callback instanceof OnOpChangedInternalListener) {
- ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName,
- persistentDeviceId);
- }
- if (sAppOpInfos[op].name != null) {
-
- callback.onOpChanged(sAppOpInfos[op].name, packageName,
- UserHandle.getUserId(uid), persistentDeviceId);
+ if (Flags.deviceAwarePermissionApisEnabled()) {
+ if (callback instanceof OnOpChangedInternalListener) {
+ ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName,
+ persistentDeviceId);
+ }
+ if (sAppOpInfos[op].name != null) {
+ callback.onOpChanged(sAppOpInfos[op].name, packageName,
+ UserHandle.getUserId(uid), persistentDeviceId);
+ }
+ } else {
+ if (callback instanceof OnOpChangedInternalListener) {
+ ((OnOpChangedInternalListener) callback).onOpChanged(op,
+ packageName);
+ }
+ if (sAppOpInfos[op].name != null) {
+ callback.onOpChanged(sAppOpInfos[op].name, packageName,
+ UserHandle.getUserId(uid));
+ }
}
}
};
@@ -8940,6 +8950,8 @@
*
* @hide
*/
+ @TestApi
+ @SuppressLint("UnflaggedApi")
public int noteOpNoThrow(int op, @NonNull AttributionSource attributionSource,
@Nullable String message) {
return noteOpNoThrow(op, attributionSource.getUid(), attributionSource.getPackageName(),
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a426eda..70d2c7a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4816,9 +4816,7 @@
* @see android.net.thread.ThreadNetworkManager
* @hide
*/
- // TODO (b/325886480): update the flag to
- // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM"
- @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform")
+ @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM)
@SystemApi
public static final String THREAD_NETWORK_SERVICE = "thread_network";
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7a015cd..240cff3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3974,9 +3974,7 @@
* The device is capable of communicating with other devices via
* <a href="https://www.threadgroup.org">Thread</a> networking protocol.
*/
- // TODO (b/325886480): update the flag to
- // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM"
- @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform")
+ @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM)
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java
index 6e53fd9..3d8ccaa 100644
--- a/core/java/android/credentials/GetCandidateCredentialsResponse.java
+++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java
@@ -18,7 +18,7 @@
import android.annotation.Hide;
import android.annotation.NonNull;
-import android.app.PendingIntent;
+import android.content.Intent;
import android.credentials.selection.GetCredentialProviderData;
import android.os.Parcel;
import android.os.Parcelable;
@@ -39,32 +39,22 @@
@NonNull
private final List<GetCredentialProviderData> mCandidateProviderDataList;
- private final PendingIntent mPendingIntent;
+ @NonNull
+ private final Intent mIntent;
/**
* @hide
*/
@Hide
public GetCandidateCredentialsResponse(
- GetCredentialResponse getCredentialResponse
- ) {
- mCandidateProviderDataList = null;
- mPendingIntent = null;
- }
-
- /**
- * @hide
- */
- @Hide
- public GetCandidateCredentialsResponse(
- List<GetCredentialProviderData> candidateProviderDataList,
- PendingIntent pendingIntent
+ @NonNull List<GetCredentialProviderData> candidateProviderDataList,
+ @NonNull Intent intent
) {
Preconditions.checkCollectionNotEmpty(
candidateProviderDataList,
/*valueName=*/ "candidateProviderDataList");
mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList);
- mPendingIntent = pendingIntent;
+ mIntent = intent;
}
/**
@@ -81,8 +71,9 @@
*
* @hide
*/
- public PendingIntent getPendingIntent() {
- return mPendingIntent;
+ @NonNull
+ public Intent getIntent() {
+ return mIntent;
}
protected GetCandidateCredentialsResponse(Parcel in) {
@@ -91,14 +82,13 @@
mCandidateProviderDataList = candidateProviderDataList;
AnnotationValidations.validate(NonNull.class, null, mCandidateProviderDataList);
-
- mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
+ mIntent = in.readTypedObject(Intent.CREATOR);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(mCandidateProviderDataList);
- dest.writeTypedObject(mPendingIntent, flags);
+ dest.writeTypedObject(mIntent, flags);
}
@Override
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
index 510b14e..e28f345 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
@@ -99,7 +99,11 @@
mDeadZone = new android.inputmethodservice.navigationbar.DeadZone(this);
- getImeSwitchButton().setOnClickListener(view -> view.getContext()
+ getBackButton().setLongClickable(false);
+
+ final ButtonDispatcher imeSwitchButton = getImeSwitchButton();
+ imeSwitchButton.setLongClickable(false);
+ imeSwitchButton.setOnClickListener(view -> view.getContext()
.getSystemService(InputMethodManager.class).showInputMethodPicker());
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index be17d7c..ccb534e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1920,9 +1920,7 @@
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
*/
- // TODO (b/325886480): update the flag to
- // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_USER_RESTRICTION_ENABLED"
- @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled")
+ @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_USER_RESTRICTION_ENABLED)
public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
/**
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index 2cb16d337b..c21895a 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -3,11 +3,15 @@
# PLEASE ASSIGN NEW BUGS TO android-storage-triage@, NOT TO INDIVIDUAL PEOPLE
# Android Storage Team
+aibra@google.com
+akgaurav@google.com
alukin@google.com
ankitavyas@google.com
dipankarb@google.com
gargshivam@google.com
+ishneet@google.com
krishang@google.com
+oeissa@google.com
riyaghai@google.com
sahanas@google.com
shikhamalhotra@google.com
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 460b4dd..141ffc9 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -359,8 +359,7 @@
new PermissionGroupUsage(usage.packageName, usage.uid, usage.lastAccessTime,
permGroup,
usage.isRunning, isPhone, usage.attributionTag, attributionLabel,
- usagesWithLabels.valueAt(usageNum),
- VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT));
+ usagesWithLabels.valueAt(usageNum), deviceId));
}
}
diff --git a/core/java/android/service/chooser/flags.aconfig b/core/java/android/service/chooser/flags.aconfig
index 00236df..d72441f 100644
--- a/core/java/android/service/chooser/flags.aconfig
+++ b/core/java/android/service/chooser/flags.aconfig
@@ -27,3 +27,14 @@
description: "Provides additional callbacks with information about user actions in ChooserResult"
bug: "263474465"
}
+
+flag {
+ name: "legacy_chooser_pinning_removal"
+ namespace: "intentresolver"
+ description: "Removing pinning functionality from the legacy chooser (used by partial screenshare)"
+ bug: "301068735"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index ad326e4..a2f767d 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -102,6 +102,7 @@
per-file IWindow*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
per-file RemoteAnimation*.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file RemoteAnimation*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ScreenRecordingCallbacks.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file *SurfaceControl*.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file SurfaceControl*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
per-file SurfaceSession.java = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/view/RoundedCorners.java b/core/java/android/view/RoundedCorners.java
index f68cc69..1f841bf 100644
--- a/core/java/android/view/RoundedCorners.java
+++ b/core/java/android/view/RoundedCorners.java
@@ -198,6 +198,12 @@
radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius);
}
array.recycle();
+ // For devices with round displays (e.g. watches) that don't otherwise provide the rounded
+ // corner radius via resource overlays, we can infer the corner radius directly from the
+ // display size.
+ if (radius == 0 && res.getConfiguration().isScreenRound()) {
+ radius = res.getDisplayMetrics().widthPixels / 2;
+ }
return radius;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cbb3be7..042af1f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15314,6 +15314,7 @@
* {@link #isLongClickable()}, {@link #isContextClickable()},
* {@link #isScreenReaderFocusable()}, or {@link #isFocusable()}
* <li>Has an {@link AccessibilityDelegate}
+ * <li>Has an {@link AccessibilityNodeProvider}
* <li>Has an interaction listener, e.g. {@link OnTouchListener},
* {@link OnKeyListener}, etc.
* <li>Is an accessibility live region, e.g.
@@ -15346,7 +15347,8 @@
}
return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility()
- || hasListenersForAccessibility() || mAccessibilityDelegate != null
+ || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null
+ || getAccessibilityDelegate() != null
|| getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE
|| isAccessibilityPane() || isAccessibilityHeading();
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 7c9678f..16fecc1 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -497,6 +497,25 @@
* @hide
*/
@TestApi
+ public InputMethodInfo(@NonNull String packageName, @NonNull String className,
+ @NonNull CharSequence label, @NonNull String settingsActivity,
+ @NonNull String languageSettingsActivity, boolean supportStylusHandwriting,
+ @NonNull String stylusHandwritingSettingsActivityAttr) {
+ this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
+ settingsActivity, languageSettingsActivity, null /* subtypes */,
+ 0 /* isDefaultResId */, false /* forceDefault */,
+ true /* supportsSwitchingToNextInputMethod */,
+ false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
+ false /* isVirtualDeviceOnly */, 0 /* handledConfigChanges */,
+ supportStylusHandwriting, false /* supportConnectionlessStylusHandwriting */,
+ stylusHandwritingSettingsActivityAttr, false /* inlineSuggestionsEnabled */);
+ }
+
+ /**
+ * Test API for creating a built-in input method to verify stylus handwriting.
+ * @hide
+ */
+ @TestApi
@FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING)
public InputMethodInfo(@NonNull String packageName, @NonNull String className,
@NonNull CharSequence label, @NonNull String settingsActivity,
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3bce155..f349ae9 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -3490,8 +3490,7 @@
return false;
}
mServedView = mNextServedView;
- if (initiationWithoutInputConnection() && mServedView.onCheckIsTextEditor()
- && mServedView.isHandwritingDelegate()) {
+ if (initiationWithoutInputConnection() && mServedView.isHandwritingDelegate()) {
mServedView.getViewRootImpl().getHandwritingInitiator().onDelegateViewFocused(
mServedView);
}
diff --git a/core/java/android/window/flags/OWNERS b/core/java/android/window/flags/OWNERS
index 3fa3760..fd73d35 100644
--- a/core/java/android/window/flags/OWNERS
+++ b/core/java/android/window/flags/OWNERS
@@ -1,2 +1,3 @@
per-file responsible_apis.aconfig = file:/BAL_OWNERS
per-file large_screen_experiences_app_compat.aconfig = file:/LSE_APP_COMPAT_OWNERS
+per-file accessibility.aconfig = file:/core/java/android/view/accessibility/OWNERS
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 86d3037..29669d3 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -96,6 +96,7 @@
import android.provider.OpenableColumns;
import android.provider.Settings;
import android.service.chooser.ChooserTarget;
+import android.service.chooser.Flags;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.HashedStringCache;
@@ -2543,6 +2544,9 @@
@Override
public boolean isComponentPinned(ComponentName name) {
+ if (Flags.legacyChooserPinningRemoval()) {
+ return false;
+ }
return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
}
@@ -3147,6 +3151,10 @@
}
private boolean shouldShowTargetDetails(TargetInfo ti) {
+ if (Flags.legacyChooserPinningRemoval()) {
+ // Never show the long press menu if we've removed pinning.
+ return false;
+ }
ComponentName nearbyShare = getNearbySharingComponent();
// Suppress target details for nearby share to hide pin/unpin action
boolean isNearbyShare = nearbyShare != null && nearbyShare.equals(
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index 73df5e8..5e89d06 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -421,6 +421,8 @@
@NonNull
private String[] mUsesStaticLibrariesSorted;
+ private boolean mAppMetadataFileInApk = false;
+
@NonNull
public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath,
@NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp,
@@ -1063,6 +1065,11 @@
return memtagMode;
}
+ @Override
+ public boolean isAppMetadataFileInApk() {
+ return mAppMetadataFileInApk;
+ }
+
@Nullable
@Override
public Bundle getMetaData() {
@@ -2151,6 +2158,12 @@
}
@Override
+ public PackageImpl setAppMetadataFileInApk(boolean fileInApk) {
+ mAppMetadataFileInApk = fileInApk;
+ return this;
+ }
+
+ @Override
public PackageImpl setMetaData(@Nullable Bundle value) {
metaData = value;
return this;
@@ -3264,6 +3277,7 @@
dest.writeLong(this.mBooleans);
dest.writeLong(this.mBooleans2);
dest.writeBoolean(this.mAllowCrossUidActivitySwitchFromBelow);
+ dest.writeBoolean(this.mAppMetadataFileInApk);
}
public PackageImpl(Parcel in) {
@@ -3426,6 +3440,7 @@
this.mBooleans = in.readLong();
this.mBooleans2 = in.readLong();
this.mAllowCrossUidActivitySwitchFromBelow = in.readBoolean();
+ this.mAppMetadataFileInApk = in.readBoolean();
assignDerivedFields();
assignDerivedFields2();
diff --git a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
index 66cfb69..3c26a7c 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
@@ -127,4 +127,7 @@
ParsedPackage setDirectBootAware(boolean directBootAware);
ParsedPackage setPersistent(boolean persistent);
+
+ /** Retrieves whether the apk contains a app metadata file. */
+ boolean isAppMetadataFileInApk();
}
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
index 5d185af..5ab17a6 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
@@ -133,6 +133,9 @@
@Nullable SparseArray<int[]> splitDependencies
);
+ /** Sets whether the apk contains a app metadata file. */
+ ParsingPackage setAppMetadataFileInApk(boolean fileInApk);
+
ParsingPackage setMetaData(Bundle metaData);
ParsingPackage setForceQueryable(boolean forceQueryable);
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index 2e6053d..00c4827 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -46,6 +46,7 @@
import android.content.pm.ConfigurationInfo;
import android.content.pm.FeatureGroupInfo;
import android.content.pm.FeatureInfo;
+import android.content.pm.Flags;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.Property;
@@ -163,6 +164,8 @@
*/
public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
+ public static final String APP_METADATA_FILE_NAME = "app.metadata";
+
/**
* Path prefix for apps on expanded storage
*/
@@ -636,6 +639,11 @@
pkg.setSigningDetails(SigningDetails.UNKNOWN);
}
+ if (Flags.aslInApkAppMetadataSource()
+ && ArrayUtils.contains(assets.list(""), APP_METADATA_FILE_NAME)) {
+ pkg.setAppMetadataFileInApk(true);
+ }
+
return input.success(pkg);
} catch (Exception e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
@@ -686,7 +694,8 @@
*/
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags,
- boolean shouldSkipComponents) throws XmlPullParserException, IOException {
+ boolean shouldSkipComponents)
+ throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 0938ce17..3ed9f49 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1965,7 +1965,7 @@
// If this zygote isn't root, it won't be able to create a process group,
// since the directory is owned by root.
- if (!is_system_server && getuid() == 0) {
+ if (getuid() == 0) {
const int rc = createProcessGroup(uid, getpid());
if (rc != 0) {
fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing "
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 525bdc9..487b5be 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2281,7 +2281,7 @@
<!-- @SystemApi @hide Allows changing Thread network state and access to Thread network
credentials such as Network Key and PSKc.
<p>Not for use by third-party applications.
- @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") -->
+ @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") -->
<permission android:name="android.permission.THREAD_NETWORK_PRIVILEGED"
android:protectionLevel="signature|privileged" />
@@ -3629,7 +3629,7 @@
<!-- Allows an application to set policy related to <a
href="https://www.threadgroup.org">Thread</a> network.
- @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled")
+ @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK"
android:protectionLevel="internal|role" />
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 37e6780..e72beee 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -28,10 +28,19 @@
visibility: ["//visibility:private"],
}
+java_defaults {
+ name: "FrameworksCoreTests-resources",
+ aaptflags: [
+ "-0 .dat",
+ "-0 .gld",
+ "-c fa",
+ ],
+ resource_dirs: ["res"],
+}
+
android_test {
name: "FrameworksCoreTests",
- // FrameworksCoreTestsRavenwood references the .aapt.srcjar
- use_resource_processor: false,
+ defaults: ["FrameworksCoreTests-resources"],
srcs: [
"src/**/*.java",
@@ -117,7 +126,6 @@
certificate: "platform",
- resource_dirs: ["res"],
resource_zips: [":FrameworksCoreTests_apks_as_resources"],
java_resources: [":FrameworksCoreTests_unit_test_cert_der"],
@@ -128,6 +136,24 @@
],
}
+// FrameworksCoreTestsRavenwood pulls in the R.java class from this one.
+// Note, "FrameworksCoreTests" and "FrameworksCoreTests-resonly" _might_ not have indentical
+// R.java (not sure if there's a guarantee), but that doesn't matter as long as
+// FrameworksCoreTestsRavenwood consistently uses the R definition in this module.
+android_app {
+ name: "FrameworksCoreTests-resonly",
+ defaults: ["FrameworksCoreTests-resources"],
+
+ // FrameworksCoreTestsRavenwood references the .aapt.srcjar
+ use_resource_processor: false,
+ libs: [
+ "framework-res",
+ "android.test.runner",
+ "org.apache.http.legacy",
+ ],
+ sdk_version: "core_platform",
+}
+
// Rules to copy all the test apks to the intermediate raw resource directory
java_genrule {
name: "FrameworksCoreTests_apks_as_resources",
@@ -225,7 +251,11 @@
"src/com/android/internal/util/**/*.java",
"src/com/android/internal/power/EnergyConsumerStatsTest.java",
- ":FrameworksCoreTests{.aapt.srcjar}",
+ // Pull in R.java from FrameworksCoreTests-resonly, not from FrameworksCoreTests,
+ // to avoid having a dependency to FrameworksCoreTests.
+ // This way, when updating source files and running this test, we don't need to
+ // rebuild the entire FrameworksCoreTests, which would be slow.
+ ":FrameworksCoreTests-resonly{.aapt.srcjar}",
":FrameworksCoreTests-aidl",
":FrameworksCoreTests-helpers",
":FrameworksCoreTestDoubles-sources",
diff --git a/core/tests/coretests/src/android/view/RoundedCornersTest.java b/core/tests/coretests/src/android/view/RoundedCornersTest.java
index 07ef33a..ec665ad 100644
--- a/core/tests/coretests/src/android/view/RoundedCornersTest.java
+++ b/core/tests/coretests/src/android/view/RoundedCornersTest.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.content.res.Configuration.SCREENLAYOUT_ROUND_NO;
+import static android.content.res.Configuration.SCREENLAYOUT_ROUND_YES;
import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT;
import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT;
import static android.view.RoundedCorner.POSITION_TOP_LEFT;
@@ -28,22 +30,47 @@
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.platform.test.annotations.Presubmit;
+import android.util.DisplayMetrics;
import android.util.Pair;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
+
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
@SmallTest
@Presubmit
public class RoundedCornersTest {
+ @Mock
+ DisplayMetrics mMockDisplayMetrics;
+ @Mock
+ Resources mMockResources;
+ @Mock TypedArray mMockTypedArray;
+ Configuration mConfiguration;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mConfiguration = Configuration.EMPTY;
+ }
+
final RoundedCorners mRoundedCorners = new RoundedCorners(
new RoundedCorner(POSITION_TOP_LEFT, 10, 10, 10),
new RoundedCorner(POSITION_TOP_RIGHT, 10, 190, 10),
@@ -199,4 +226,63 @@
assertThat(RoundedCorners.fromRadii(radius, 200, 300),
not(sameInstance(cached)));
}
+
+ @Test
+ public void testGetRoundedCornerRadius_withRoundDevice_usesDisplayRadiusAsDefault() {
+ final int displayWidth = 400;
+ mConfiguration.screenLayout = SCREENLAYOUT_ROUND_YES;
+ mMockDisplayMetrics.widthPixels = displayWidth;
+
+ when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+ when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+ when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+ .thenReturn(new String[]{"0"});
+ when(mMockTypedArray.length()).thenReturn(0);
+ when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+ when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+ .thenReturn(0);
+
+
+ int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+ assertEquals((displayWidth / 2), radius);
+ }
+
+ @Test
+ public void testGetRoundedCornerRadius_withRoundDevice_usesOverlayIfProvided() {
+ final int displayWidth = 400;
+ final int overlayValue = 199;
+ mConfiguration.screenLayout = SCREENLAYOUT_ROUND_YES;
+ mMockDisplayMetrics.widthPixels = displayWidth;
+
+ when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+ when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+ when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+ .thenReturn(new String[]{"0"});
+ when(mMockTypedArray.length()).thenReturn(0);
+ when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+ when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+ .thenReturn(overlayValue);
+
+ int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+ assertEquals(overlayValue, radius);
+ }
+
+ @Test
+ public void testGetRoundedCornerRadius_withNonRoundDevice_noDisplayDefault() {
+ final int displayWidth = 400;
+ mConfiguration.screenLayout = SCREENLAYOUT_ROUND_NO;
+ mMockDisplayMetrics.widthPixels = displayWidth;
+
+ when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+ when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+ when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+ .thenReturn(new String[]{"0"});
+ when(mMockTypedArray.length()).thenReturn(0);
+ when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+ when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+ .thenReturn(0);
+
+ int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+ assertEquals(0, radius);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index c70a821..9130edf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -470,10 +470,12 @@
}
final float cornerRadius;
- if (a.hasRoundedCorners() && isTask) {
- // hasRoundedCorners is currently only enabled for tasks
+ if (a.hasRoundedCorners()) {
+ final int displayId = isTask ? change.getTaskInfo().displayId
+ : info.getRoot(TransitionUtil.rootIndexFor(change, info))
+ .getDisplayId();
final Context displayContext =
- mDisplayController.getDisplayContext(change.getTaskInfo().displayId);
+ mDisplayController.getDisplayContext(displayId);
cornerRadius = displayContext == null ? 0
: ScreenDecorationsUtils.getWindowCornerRadius(displayContext);
} else {
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index ea136ed..c90c441 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -1079,7 +1079,7 @@
* @return one of the values that can be set in {@link Builder#setEncoding(int)} or
* {@link AudioFormat#ENCODING_INVALID} if not set.
*/
- public @Encoding int getEncoding() {
+ public @EncodingCanBeInvalid int getEncoding() {
return mEncoding;
}
@@ -1486,6 +1486,44 @@
@Retention(RetentionPolicy.SOURCE)
public @interface Encoding {}
+ /** @hide same as @Encoding, but adding ENCODING_INVALID */
+ @IntDef(flag = false, prefix = "ENCODING", value = {
+ ENCODING_INVALID,
+ ENCODING_DEFAULT,
+ ENCODING_PCM_16BIT,
+ ENCODING_PCM_8BIT,
+ ENCODING_PCM_FLOAT,
+ ENCODING_AC3,
+ ENCODING_E_AC3,
+ ENCODING_DTS,
+ ENCODING_DTS_HD,
+ ENCODING_MP3,
+ ENCODING_AAC_LC,
+ ENCODING_AAC_HE_V1,
+ ENCODING_AAC_HE_V2,
+ ENCODING_IEC61937,
+ ENCODING_DOLBY_TRUEHD,
+ ENCODING_AAC_ELD,
+ ENCODING_AAC_XHE,
+ ENCODING_AC4,
+ ENCODING_E_AC3_JOC,
+ ENCODING_DOLBY_MAT,
+ ENCODING_OPUS,
+ ENCODING_PCM_24BIT_PACKED,
+ ENCODING_PCM_32BIT,
+ ENCODING_MPEGH_BL_L3,
+ ENCODING_MPEGH_BL_L4,
+ ENCODING_MPEGH_LC_L3,
+ ENCODING_MPEGH_LC_L4,
+ ENCODING_DTS_UHD_P1,
+ ENCODING_DRA,
+ ENCODING_DTS_HD_MA,
+ ENCODING_DTS_UHD_P2,
+ ENCODING_DSD }
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EncodingCanBeInvalid {}
+
/** @hide */
public static final int[] SURROUND_SOUND_ENCODING = {
ENCODING_AC3,
diff --git a/packages/CrashRecovery/framework/Android.bp b/packages/CrashRecovery/framework/Android.bp
index c0d93531..9480327 100644
--- a/packages/CrashRecovery/framework/Android.bp
+++ b/packages/CrashRecovery/framework/Android.bp
@@ -3,7 +3,7 @@
module_type: "filegroup",
config_namespace: "ANDROID",
bool_variables: [
- "move_crashrecovery_files",
+ "crashrecovery_files_in_platform",
],
properties: [
"srcs",
@@ -12,14 +12,13 @@
platform_filegroup {
name: "framework-crashrecovery-sources",
- srcs: [
- "java/**/*.java",
- "java/**/*.aidl",
- ],
soong_config_variables: {
- // if the flag is enabled, then files would be moved to module
- move_crashrecovery_files: {
- srcs: [],
+ // if this flag is enabled, then files are part of platform
+ crashrecovery_files_in_platform: {
+ srcs: [
+ "java/**/*.java",
+ "java/**/*.aidl",
+ ],
},
},
path: "java",
@@ -31,7 +30,7 @@
module_type: "filegroup",
config_namespace: "ANDROID",
bool_variables: [
- "move_crashrecovery_files",
+ "crashrecovery_files_in_module",
],
properties: [
"srcs",
@@ -40,10 +39,9 @@
module_filegroup {
name: "framework-crashrecovery-module-sources",
- srcs: [],
soong_config_variables: {
- // if the flag is enabled, then files would be moved to module
- move_crashrecovery_files: {
+ // if this flag is enabled, then files are part of module
+ crashrecovery_files_in_module: {
srcs: [
"java/**/*.java",
"java/**/*.aidl",
diff --git a/packages/CrashRecovery/services/Android.bp b/packages/CrashRecovery/services/Android.bp
index ab10b5a..961b41f 100644
--- a/packages/CrashRecovery/services/Android.bp
+++ b/packages/CrashRecovery/services/Android.bp
@@ -3,7 +3,7 @@
module_type: "filegroup",
config_namespace: "ANDROID",
bool_variables: [
- "move_crashrecovery_files",
+ "crashrecovery_files_in_platform",
],
properties: [
"srcs",
@@ -12,15 +12,14 @@
platform_filegroup {
name: "services-crashrecovery-sources",
- srcs: [
- "java/**/*.java",
- "java/**/*.aidl",
- ":statslog-crashrecovery-java-gen",
- ],
soong_config_variables: {
- // if the flag is enabled, then files would be moved to module
- move_crashrecovery_files: {
- srcs: [],
+ // if this flag is enabled, then files are part of platform
+ crashrecovery_files_in_platform: {
+ srcs: [
+ "java/**/*.java",
+ "java/**/*.aidl",
+ ":statslog-crashrecovery-java-gen",
+ ],
},
},
visibility: ["//frameworks/base:__subpackages__"],
@@ -31,7 +30,7 @@
module_type: "filegroup",
config_namespace: "ANDROID",
bool_variables: [
- "move_crashrecovery_files",
+ "crashrecovery_files_in_module",
],
properties: [
"srcs",
@@ -40,10 +39,9 @@
module_filegroup {
name: "services-crashrecovery-module-sources",
- srcs: [],
soong_config_variables: {
- // if the flag is enabled, then files would be moved to module
- move_crashrecovery_files: {
+ // if this flag is enabled, then files are part of module
+ crashrecovery_files_in_module: {
srcs: [
"java/**/*.java",
"java/**/*.aidl",
diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
index ce8fb65..5d71b7d 100644
--- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
@@ -38,13 +38,13 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.BackgroundThread;
import android.util.LongArrayQueue;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 5fb47dd..0fb9327 100644
--- a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -75,6 +75,9 @@
private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
| ApplicationInfo.FLAG_SYSTEM;
+ private static final String PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG =
+ "persist.device_config.configuration.disable_high_impact_rollback";
+
private final Context mContext;
private final Handler mHandler;
private final ApexManager mApexManager;
@@ -605,6 +608,10 @@
// Apply all available low impact rollbacks.
mHandler.post(() -> rollbackAllLowImpact(availableRollbacks, rollbackReason));
} else if (minRollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH) {
+ // Check disable_high_impact_rollback device config before performing rollback
+ if (SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) {
+ return;
+ }
// Rollback one package at a time. If that doesn't resolve the issue, rollback
// next with same impact level.
mHandler.post(() -> rollbackHighImpact(availableRollbacks, rollbackReason));
@@ -718,7 +725,9 @@
impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70;
break;
case PackageManager.ROLLBACK_USER_IMPACT_HIGH:
- impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_90;
+ if (!SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) {
+ impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_90;
+ }
break;
default:
impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
diff --git a/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java b/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
new file mode 100644
index 0000000..a6ae68f
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
@@ -0,0 +1,103 @@
+/*
+ * * Copyright (C) 2024 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.util;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Thread for asynchronous event processing. This thread is configured as
+ * {@link android.os.Process#THREAD_PRIORITY_BACKGROUND}, which means fewer CPU
+ * resources will be dedicated to it, and it will "have less chance of impacting
+ * the responsiveness of the user interface."
+ * <p>
+ * This thread is best suited for tasks that the user is not actively waiting
+ * for, or for tasks that the user expects to be executed eventually.
+ *
+ * @see com.android.internal.os.BackgroundThread
+ *
+ * TODO: b/326916057 depend on modules-utils-backgroundthread instead
+ * @hide
+ */
+public final class BackgroundThread extends HandlerThread {
+ private static final Object sLock = new Object();
+
+ @GuardedBy("sLock")
+ private static BackgroundThread sInstance;
+ @GuardedBy("sLock")
+ private static Handler sHandler;
+ @GuardedBy("sLock")
+ private static HandlerExecutor sHandlerExecutor;
+
+ private BackgroundThread() {
+ super(BackgroundThread.class.getName(), android.os.Process.THREAD_PRIORITY_BACKGROUND);
+ }
+
+ @GuardedBy("sLock")
+ private static void ensureThreadLocked() {
+ if (sInstance == null) {
+ sInstance = new BackgroundThread();
+ sInstance.start();
+ sHandler = new Handler(sInstance.getLooper());
+ sHandlerExecutor = new HandlerExecutor(sHandler);
+ }
+ }
+
+ /**
+ * Get the singleton instance of this class.
+ *
+ * @return the singleton instance of this class
+ */
+ @NonNull
+ public static BackgroundThread get() {
+ synchronized (sLock) {
+ ensureThreadLocked();
+ return sInstance;
+ }
+ }
+
+ /**
+ * Get the singleton {@link Handler} for this class.
+ *
+ * @return the singleton {@link Handler} for this class.
+ */
+ @NonNull
+ public static Handler getHandler() {
+ synchronized (sLock) {
+ ensureThreadLocked();
+ return sHandler;
+ }
+ }
+
+ /**
+ * Get the singleton {@link Executor} for this class.
+ *
+ * @return the singleton {@link Executor} for this class.
+ */
+ @NonNull
+ public static Executor getExecutor() {
+ synchronized (sLock) {
+ ensureThreadLocked();
+ return sHandlerExecutor;
+ }
+ }
+}
diff --git a/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java b/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
new file mode 100644
index 0000000..948ebcca
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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.util;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * An adapter {@link Executor} that posts all executed tasks onto the given
+ * {@link Handler}.
+ *
+ * TODO: b/326916057 depend on modules-utils-backgroundthread instead
+ * @hide
+ */
+public class HandlerExecutor implements Executor {
+ private final Handler mHandler;
+
+ public HandlerExecutor(@NonNull Handler handler) {
+ mHandler = Objects.requireNonNull(handler);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ if (!mHandler.post(command)) {
+ throw new RejectedExecutionException(mHandler + " is shutting down");
+ }
+ }
+}
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
index a5f227a..02320a1 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
@@ -127,10 +127,10 @@
userName = credentialEntry.username.toString(),
displayName = credentialEntry.displayName?.toString(),
icon = credentialEntry.icon.loadDrawable(context),
- shouldTintIcon = credentialEntry.isDefaultIcon,
+ shouldTintIcon = credentialEntry.hasDefaultIcon,
lastUsedTimeMillis = credentialEntry.lastUsedTime,
isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
- credentialEntry.autoSelectAllowedFromOption,
+ credentialEntry.isAutoSelectAllowedFromOption,
)
)
}
@@ -148,10 +148,10 @@
userName = credentialEntry.username.toString(),
displayName = credentialEntry.displayName?.toString(),
icon = credentialEntry.icon.loadDrawable(context),
- shouldTintIcon = credentialEntry.isDefaultIcon,
+ shouldTintIcon = credentialEntry.hasDefaultIcon,
lastUsedTimeMillis = credentialEntry.lastUsedTime,
isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
- credentialEntry.autoSelectAllowedFromOption,
+ credentialEntry.isAutoSelectAllowedFromOption,
)
)
}
@@ -170,10 +170,10 @@
userName = credentialEntry.title.toString(),
displayName = credentialEntry.subtitle?.toString(),
icon = credentialEntry.icon.loadDrawable(context),
- shouldTintIcon = credentialEntry.isDefaultIcon,
+ shouldTintIcon = credentialEntry.hasDefaultIcon,
lastUsedTimeMillis = credentialEntry.lastUsedTime,
isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
- credentialEntry.autoSelectAllowedFromOption,
+ credentialEntry.isAutoSelectAllowedFromOption,
)
)
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 0f17217..28c42fb 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -213,7 +213,7 @@
autofillIdToProvidersMap.forEach { (autofillId, providers) ->
validFillResponse = processProvidersForAutofillId(
filLRequest, autofillId, providers, entryIconMap, fillResponseBuilder,
- getCredResponse.pendingIntent)
+ getCredResponse.intent)
.or(validFillResponse)
}
if (!validFillResponse) {
@@ -229,7 +229,7 @@
providerDataList: ArrayList<GetCredentialProviderData>,
entryIconMap: Map<String, Icon>,
fillResponseBuilder: FillResponse.Builder,
- bottomSheetPendingIntent: PendingIntent?
+ bottomSheetIntent: Intent
): Boolean {
val providerList = GetFlowUtils.toProviderList(
providerDataList,
@@ -267,6 +267,8 @@
}
}
}
+ bottomSheetIntent.putExtra(
+ ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, providerDataList)
providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@{
val primaryEntry = it.sortedCredentialEntryList.first()
val pendingIntent = primaryEntry.pendingIntent
@@ -330,16 +332,16 @@
datasetAdded = true
i++
- if (i == lastDropdownDatasetIndex && bottomSheetPendingIntent != null) {
- addDropdownMoreOptionsPresentation(bottomSheetPendingIntent, autofillId,
+ if (i == lastDropdownDatasetIndex) {
+ addDropdownMoreOptionsPresentation(bottomSheetIntent, autofillId,
fillResponseBuilder)
}
}
val pinnedSpec = getLastInlinePresentationSpec(inlinePresentationSpecs,
inlinePresentationSpecsCount)
- if (datasetAdded && bottomSheetPendingIntent != null && pinnedSpec != null) {
- addPinnedInlineSuggestion(bottomSheetPendingIntent, pinnedSpec, autofillId,
- fillResponseBuilder, providerDataList)
+ if (datasetAdded && pinnedSpec != null) {
+ addPinnedInlineSuggestion(pinnedSpec, autofillId,
+ fillResponseBuilder, bottomSheetIntent)
}
return datasetAdded
}
@@ -370,13 +372,14 @@
}
private fun addDropdownMoreOptionsPresentation(
- bottomSheetPendingIntent: PendingIntent,
+ bottomSheetIntent: Intent,
autofillId: AutofillId,
fillResponseBuilder: FillResponse.Builder
) {
val presentationBuilder = Presentations.Builder()
.setMenuPresentation(
RemoteViewsFactory.createMoreSignInOptionsPresentation(this))
+ val pendingIntent = setUpBottomSheetPendingIntent(bottomSheetIntent)
fillResponseBuilder.addDataset(
Dataset.Builder()
@@ -385,7 +388,7 @@
Field.Builder().setPresentations(
presentationBuilder.build())
.build())
- .setAuthentication(bottomSheetPendingIntent.intentSender)
+ .setAuthentication(pendingIntent.intentSender)
.build()
)
}
@@ -401,37 +404,41 @@
}
private fun addPinnedInlineSuggestion(
- bottomSheetPendingIntent: PendingIntent,
spec: InlinePresentationSpec,
autofillId: AutofillId,
fillResponseBuilder: FillResponse.Builder,
- providerDataList: ArrayList<GetCredentialProviderData>
+ bottomSheetIntent: Intent
) {
+ val pendingIntent = setUpBottomSheetPendingIntent(bottomSheetIntent)
+
val dataSetBuilder = Dataset.Builder()
val sliceBuilder = InlineSuggestionUi
- .newContentBuilder(bottomSheetPendingIntent)
+ .newContentBuilder(pendingIntent)
.setStartIcon(Icon.createWithResource(this,
com.android.credentialmanager.R.drawable.more_horiz_24px))
val presentationBuilder = Presentations.Builder()
.setInlinePresentation(InlinePresentation(
sliceBuilder.build().slice, spec, /* pinned= */ true))
- val extrasIntent = Intent()
- extrasIntent.putExtra(ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, providerDataList)
-
fillResponseBuilder.addDataset(
dataSetBuilder
.setField(
autofillId,
Field.Builder().setPresentations(
- presentationBuilder.build())
- .build())
- .setAuthentication(bottomSheetPendingIntent.intentSender)
- .setCredentialFillInIntent(extrasIntent)
+ presentationBuilder.build()
+ ).build()
+ )
+ .setAuthentication(pendingIntent.intentSender)
.build()
)
}
+ private fun setUpBottomSheetPendingIntent(intent: Intent): PendingIntent {
+ intent.setAction(java.util.UUID.randomUUID().toString())
+ return PendingIntent.getActivity(this, /*requestCode=*/0, intent,
+ PendingIntent.FLAG_MUTABLE, /*options=*/null)
+ }
+
/**
* Maps Autofill Id to provider list. For example, passing in a provider info
*
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index bed95a5..e63232a 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -230,6 +230,7 @@
extra_check_modules: ["SystemUILintChecker"],
warning_checks: ["MissingApacheLicenseDetector"],
},
+ skip_jarjar_repackage: true,
}
filegroup {
diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp
index c12084d..dfb3a55 100644
--- a/packages/SystemUI/compose/features/Android.bp
+++ b/packages/SystemUI/compose/features/Android.bp
@@ -44,4 +44,5 @@
],
kotlincflags: ["-Xjvm-default=all"],
+ skip_jarjar_repackage: true,
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 622a4f0..609f314 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -274,7 +274,7 @@
widgetConfigurator: WidgetConfigurator?,
) {
var gridModifier =
- Modifier.align(Alignment.CenterStart).onGloballyPositioned { setGridCoordinates(it) }
+ Modifier.align(Alignment.TopStart).onGloballyPositioned { setGridCoordinates(it) }
var list = communalContent
var dragDropState: GridDragDropState? = null
if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) {
@@ -309,8 +309,8 @@
state = gridState,
rows = GridCells.Fixed(CommunalContentSize.FULL.span),
contentPadding = contentPadding,
- horizontalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
- verticalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
+ horizontalArrangement = Arrangement.spacedBy(32.dp),
+ verticalArrangement = Arrangement.spacedBy(32.dp),
) {
items(
count = list.size,
@@ -681,19 +681,20 @@
Box(
modifier = modifier,
) {
- val paddingInPx = with(LocalDensity.current) { CardOutlineWidth.toPx().toInt() }
+ val paddingInPx =
+ if (selected) with(LocalDensity.current) { CardOutlineWidth.toPx().toInt() } else 0
AndroidView(
modifier = Modifier.fillMaxSize().allowGestures(allowed = !viewModel.isEditMode),
factory = { context ->
- val view =
- model.appWidgetHost
- .createViewForCommunal(context, model.appWidgetId, model.providerInfo)
- .apply { updateAppWidgetSize(Bundle.EMPTY, listOf(size)) }
+ model.appWidgetHost
+ .createViewForCommunal(context, model.appWidgetId, model.providerInfo)
+ .apply { updateAppWidgetSize(Bundle.EMPTY, listOf(size)) }
+ },
+ update = { view ->
// Remove the extra padding applied to AppWidgetHostView to allow widgets to
// occupy the entire box. The added padding is now adjusted to leave only sufficient
// space for displaying the outline around the box when the widget is selected.
view.setPadding(paddingInPx)
- view
},
// For reusing composition in lazy lists.
onReset = {},
@@ -795,7 +796,7 @@
@Composable
private fun gridContentPadding(isEditMode: Boolean, toolbarSize: IntSize?): PaddingValues {
if (!isEditMode || toolbarSize == null) {
- return PaddingValues(horizontal = Dimensions.Spacing)
+ return PaddingValues(start = 48.dp, end = 48.dp, top = Dimensions.GridTopSpacing)
}
val configuration = LocalConfiguration.current
val density = LocalDensity.current
@@ -858,12 +859,13 @@
}
object Dimensions {
- val CardWidth = 464.dp
- val CardHeightFull = 630.dp
- val CardHeightHalf = 307.dp
- val CardHeightThird = 199.dp
+ val CardWidth = 424.dp
+ val CardHeightFull = 596.dp
+ val CardHeightHalf = 282.dp
+ val CardHeightThird = 177.33.dp
val CardOutlineWidth = 3.dp
- val GridHeight = CardHeightFull
+ val GridTopSpacing = 72.dp
+ val GridHeight = CardHeightFull + GridTopSpacing
val Spacing = 16.dp
// The sizing/padding of the toolbar in glanceable hub edit mode
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index be6f022..31d3fa0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.util.DisplayMetrics
+import android.view.View
import android.view.WindowManager
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@@ -45,6 +46,7 @@
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
+import com.android.systemui.shade.NotificationPanelView
import com.android.systemui.statusbar.VibratorHelper
import dagger.Lazy
import javax.inject.Inject
@@ -63,6 +65,7 @@
private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,
private val falsingManager: Lazy<FalsingManager>,
private val vibratorHelper: Lazy<VibratorHelper>,
+ private val notificationPanelView: NotificationPanelView,
) {
@Composable
fun SceneScope.LockIcon(modifier: Modifier = Modifier) {
@@ -70,6 +73,10 @@
return
}
+ notificationPanelView.findViewById<View?>(R.id.lock_icon_view)?.let {
+ notificationPanelView.removeView(it)
+ }
+
val context = LocalContext.current
AndroidView(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
index 12611cb..88f5e1b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
@@ -17,8 +17,10 @@
package com.android.systemui.communal.widgets
import android.appwidget.AppWidgetManager
+import android.appwidget.AppWidgetProviderInfo
import android.content.ComponentName
import android.content.pm.UserInfo
+import android.os.Bundle
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -33,8 +35,8 @@
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.user.domain.interactor.selectedUserInteractor
import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -43,6 +45,7 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -91,7 +94,7 @@
any<Int>(),
any<UserHandle>(),
any<ComponentName>(),
- nullable()
+ any<Bundle>(),
)
)
.thenReturn(true)
@@ -100,8 +103,14 @@
val result = underTest.allocateIdAndBindWidget(provider)
verify(appWidgetHost).allocateAppWidgetId()
- verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+ val bundle =
+ withArgCaptor<Bundle> {
+ verify(appWidgetManager)
+ .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), capture())
+ }
assertThat(result).isEqualTo(widgetId)
+ assertThat(bundle.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))
+ .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
}
@Test
@@ -117,7 +126,7 @@
any<Int>(),
any<UserHandle>(),
any<ComponentName>(),
- nullable()
+ any<Bundle>()
)
)
.thenReturn(true)
@@ -126,8 +135,14 @@
val result = underTest.allocateIdAndBindWidget(provider, user)
verify(appWidgetHost).allocateAppWidgetId()
- verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+ val bundle =
+ withArgCaptor<Bundle> {
+ verify(appWidgetManager)
+ .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), capture())
+ }
assertThat(result).isEqualTo(widgetId)
+ assertThat(bundle.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))
+ .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
}
@Test
@@ -144,14 +159,15 @@
any<Int>(),
any<UserHandle>(),
any<ComponentName>(),
- nullable()
+ any<Bundle>()
)
)
.thenReturn(false)
val result = underTest.allocateIdAndBindWidget(provider, user)
verify(appWidgetHost).allocateAppWidgetId()
- verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+ verify(appWidgetManager)
+ .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), any())
verify(appWidgetHost).deleteAppWidgetId(widgetId)
assertThat(result).isNull()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 87d25dd..6456669 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -19,8 +19,6 @@
import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;
-import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
-import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
import static com.google.common.truth.Truth.assertThat;
@@ -41,31 +39,23 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Person;
-import android.content.Context;
import android.content.Intent;
-import android.graphics.Region;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.testing.TestableLooper;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.test.filters.SmallTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
-import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.FakeGlobalSettings;
-import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.FakeSystemClock;
-import com.android.systemui.util.time.SystemClock;
import org.junit.Rule;
import org.junit.Test;
@@ -83,8 +73,8 @@
private static final String TEST_PACKAGE_NAME = "BaseHeadsUpManagerTest";
- private static final int TEST_TOUCH_ACCEPTANCE_TIME = 200;
- private static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000;
+ static final int TEST_TOUCH_ACCEPTANCE_TIME = 200;
+ static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000;
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
@@ -110,143 +100,6 @@
assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME);
}
- private final class TestableHeadsUpManager extends BaseHeadsUpManager {
-
- private HeadsUpEntry mLastCreatedEntry;
-
- TestableHeadsUpManager(Context context,
- HeadsUpManagerLogger logger,
- DelayableExecutor executor,
- GlobalSettings globalSettings,
- SystemClock systemClock,
- AccessibilityManagerWrapper accessibilityManagerWrapper,
- UiEventLogger uiEventLogger) {
- super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock,
- executor, accessibilityManagerWrapper, uiEventLogger);
-
- mTouchAcceptanceDelay = TEST_TOUCH_ACCEPTANCE_TIME;
- mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
- mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
- mStickyForSomeTimeAutoDismissTime = TEST_STICKY_AUTO_DISMISS_TIME;
-
- }
-
- @Override
- protected HeadsUpEntry createHeadsUpEntry() {
- mLastCreatedEntry = spy(super.createHeadsUpEntry());
- return mLastCreatedEntry;
- }
-
- @Override
- public int getContentFlag() {
- return FLAG_CONTENT_VIEW_CONTRACTED;
- }
-
- // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
- @Override
- public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void addSwipedOutNotification(@NonNull String key) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void extendHeadsUp() {
- throw new UnsupportedOperationException();
- }
-
- @Nullable
- @Override
- public Region getTouchableRegion() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isHeadsUpGoingAway() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void onExpandingFinished() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
- boolean animate) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setRemoteInputActive(@NonNull NotificationEntry entry,
- boolean remoteInputActive) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setTrackingHeadsUp(boolean tracking) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean shouldSwallowClick(@NonNull String key) {
- throw new UnsupportedOperationException();
- }
- }
-
- protected StatusBarNotification createSbn(int id, Notification n) {
- return new StatusBarNotification(
- TEST_PACKAGE_NAME /* pkg */,
- TEST_PACKAGE_NAME,
- id,
- null /* tag */,
- TEST_UID,
- 0 /* initialPid */,
- n,
- new UserHandle(ActivityManager.getCurrentUser()),
- null /* overrideGroupKey */,
- 0 /* postTime */);
- }
-
- protected StatusBarNotification createSbn(int id, Notification.Builder n) {
- return createSbn(id, n.build());
- }
-
- protected StatusBarNotification createSbn(int id) {
- final Notification.Builder b = new Notification.Builder(mContext, "")
- .setSmallIcon(R.drawable.ic_person)
- .setContentTitle("Title")
- .setContentText("Text");
- return createSbn(id, b);
- }
-
- protected NotificationEntry createEntry(int id, Notification n) {
- return new NotificationEntryBuilder().setSbn(createSbn(id, n)).build();
- }
-
- protected NotificationEntry createEntry(int id) {
- return new NotificationEntryBuilder().setSbn(createSbn(id)).build();
- }
-
-
private BaseHeadsUpManager createHeadsUpManager() {
return new TestableHeadsUpManager(mContext, mLogger, mExecutor, mGlobalSettings,
mSystemClock, mAccessibilityMgr, mUiEventLoggerFake);
@@ -257,7 +110,7 @@
.setSmallIcon(R.drawable.ic_person)
.setFullScreenIntent(mock(PendingIntent.class), /* highPriority */ true)
.build();
- return createEntry(id, notif);
+ return HeadsUpManagerTestUtil.createEntry(id, notif);
}
private NotificationEntry createStickyForSomeTimeEntry(int id) {
@@ -265,7 +118,7 @@
.setSmallIcon(R.drawable.ic_person)
.setFlag(FLAG_FSI_REQUESTED_BUT_DENIED, true)
.build();
- return createEntry(id, notif);
+ return HeadsUpManagerTestUtil.createEntry(id, notif);
}
private PendingIntent createFullScreenIntent() {
@@ -279,7 +132,7 @@
.setSmallIcon(R.drawable.ic_person)
.setFullScreenIntent(createFullScreenIntent(), /* highPriority */ true)
.build();
- return createEntry(id, notif);
+ return HeadsUpManagerTestUtil.createEntry(id, notif);
}
@@ -296,7 +149,7 @@
@Test
public void testShowNotification_addsEntry() {
final BaseHeadsUpManager alm = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
alm.showNotification(entry);
@@ -308,7 +161,7 @@
@Test
public void testShowNotification_autoDismisses() {
final BaseHeadsUpManager alm = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
alm.showNotification(entry);
mSystemClock.advanceTime(TEST_AUTO_DISMISS_TIME * 3 / 2);
@@ -319,7 +172,7 @@
@Test
public void testRemoveNotification_removeDeferred() {
final BaseHeadsUpManager alm = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
alm.showNotification(entry);
@@ -332,7 +185,7 @@
@Test
public void testRemoveNotification_forceRemove() {
final BaseHeadsUpManager alm = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
alm.showNotification(entry);
@@ -346,7 +199,7 @@
public void testReleaseAllImmediately() {
final BaseHeadsUpManager alm = createHeadsUpManager();
for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) {
- final NotificationEntry entry = createEntry(i);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(i, mContext);
entry.setRow(mRow);
alm.showNotification(entry);
}
@@ -359,7 +212,7 @@
@Test
public void testCanRemoveImmediately_notShownLongEnough() {
final BaseHeadsUpManager alm = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
alm.showNotification(entry);
@@ -370,7 +223,8 @@
@Test
public void testHunRemovedLogging() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+ final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+ mContext);
final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = mock(
BaseHeadsUpManager.HeadsUpEntry.class);
headsUpEntry.mEntry = notifEntry;
@@ -413,7 +267,7 @@
@Test
public void testShouldHeadsUpBecomePinned_noFSI_false() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
assertFalse(hum.shouldHeadsUpBecomePinned(entry));
}
@@ -422,7 +276,7 @@
@Test
public void testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
useAccessibilityTimeout(false);
hum.showNotification(entry);
@@ -435,7 +289,7 @@
@Test
public void testShowNotification_autoDismissesWithDefaultTimeout() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
useAccessibilityTimeout(false);
hum.showNotification(entry);
@@ -476,7 +330,7 @@
@Test
public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
useAccessibilityTimeout(true);
hum.showNotification(entry);
@@ -504,7 +358,7 @@
@Test
public void testRemoveNotification_beforeMinimumDisplayTime() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
useAccessibilityTimeout(false);
hum.showNotification(entry);
@@ -523,7 +377,7 @@
@Test
public void testRemoveNotification_afterMinimumDisplayTime() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
useAccessibilityTimeout(false);
hum.showNotification(entry);
@@ -541,7 +395,7 @@
@Test
public void testRemoveNotification_releaseImmediately() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
hum.showNotification(entry);
@@ -555,7 +409,8 @@
@Test
public void testIsSticky_rowPinnedAndExpanded_true() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+ final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+ mContext);
when(mRow.isPinned()).thenReturn(true);
notifEntry.setRow(mRow);
@@ -571,7 +426,8 @@
@Test
public void testIsSticky_remoteInputActive_true() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+ final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+ mContext);
hum.showNotification(notifEntry);
@@ -607,7 +463,8 @@
@Test
public void testIsSticky_false() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+ final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+ mContext);
hum.showNotification(notifEntry);
@@ -653,14 +510,14 @@
final BaseHeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry();
ongoingCall.setEntry(new NotificationEntryBuilder()
- .setSbn(createSbn(/* id = */ 0,
+ .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
new Notification.Builder(mContext, "")
.setCategory(Notification.CATEGORY_CALL)
.setOngoing(true)))
.build());
final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
- activeRemoteInput.setEntry(createEntry(/* id = */ 1));
+ activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
activeRemoteInput.mRemoteInputActive = true;
assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0);
@@ -675,14 +532,14 @@
final Person person = new Person.Builder().setName("person").build();
final PendingIntent intent = mock(PendingIntent.class);
incomingCall.setEntry(new NotificationEntryBuilder()
- .setSbn(createSbn(/* id = */ 0,
+ .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
new Notification.Builder(mContext, "")
.setStyle(Notification.CallStyle
.forIncomingCall(person, intent, intent))))
.build());
final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
- activeRemoteInput.setEntry(createEntry(/* id = */ 1));
+ activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
activeRemoteInput.mRemoteInputActive = true;
assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0);
@@ -712,7 +569,8 @@
@Test
public void testSetUserActionMayIndirectlyRemove() {
final BaseHeadsUpManager hum = createHeadsUpManager();
- final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+ final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+ mContext);
hum.showNotification(notifEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
similarity index 88%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
index c350de2..ec23f76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.policy;
import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;
import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
@@ -26,10 +26,10 @@
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -39,11 +39,9 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.BaseHeadsUpManagerTest;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
+import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.GlobalSettings;
@@ -61,7 +59,7 @@
import kotlinx.coroutines.flow.StateFlowKt;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest {
@Rule public MockitoRule rule = MockitoJUnit.rule();
@@ -152,7 +150,7 @@
@Test
public void testSnooze() {
final HeadsUpManager hmp = createHeadsUpManagerPhone();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
hmp.showNotification(entry);
hmp.snooze();
@@ -163,7 +161,7 @@
@Test
public void testSwipedOutNotification() {
final HeadsUpManager hmp = createHeadsUpManagerPhone();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
hmp.showNotification(entry);
hmp.addSwipedOutNotification(entry.getKey());
@@ -179,7 +177,7 @@
@Test
public void testCanRemoveImmediately_swipedOut() {
final HeadsUpManager hmp = createHeadsUpManagerPhone();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
hmp.showNotification(entry);
hmp.addSwipedOutNotification(entry.getKey());
@@ -192,8 +190,10 @@
@Test
public void testCanRemoveImmediately_notTopEntry() {
final HeadsUpManager hmp = createHeadsUpManagerPhone();
- final NotificationEntry earlierEntry = createEntry(/* id = */ 0);
- final NotificationEntry laterEntry = createEntry(/* id = */ 1);
+ final NotificationEntry earlierEntry =
+ HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
+ final NotificationEntry laterEntry =
+ HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext);
laterEntry.setRow(mRow);
hmp.showNotification(earlierEntry);
@@ -206,7 +206,7 @@
@Test
public void testExtendHeadsUp() {
final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
- final NotificationEntry entry = createEntry(/* id = */ 0);
+ final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
hmp.showNotification(entry);
hmp.extendHeadsUp();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
new file mode 100644
index 0000000..c70b03b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+import android.app.ActivityManager;
+import android.os.UserHandle;
+
+import android.content.Context;
+import android.service.notification.StatusBarNotification;
+import android.app.Notification;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+
+/**
+ * Test helper class for HeadsUpEntry creation.
+ */
+public class HeadsUpManagerTestUtil {
+
+ private static final String TEST_PACKAGE_NAME = "HeadsUpManagerTestUtil";
+ private static final int TEST_UID = 0;
+
+ protected static StatusBarNotification createSbn(int id, Notification.Builder n) {
+ return createSbn(id, n.build());
+ }
+
+ protected static StatusBarNotification createSbn(int id, Context context) {
+ final Notification.Builder b = new Notification.Builder(context, "")
+ .setSmallIcon(com.android.systemui.res.R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text");
+ return createSbn(id, b);
+ }
+
+ protected static StatusBarNotification createSbn(int id, Notification n) {
+ return new StatusBarNotification(
+ TEST_PACKAGE_NAME /* pkg */,
+ TEST_PACKAGE_NAME,
+ id,
+ null /* tag */,
+ TEST_UID,
+ 0 /* initialPid */,
+ n,
+ new UserHandle(ActivityManager.getCurrentUser()),
+ null /* overrideGroupKey */,
+ 0 /* postTime */);
+ }
+
+ protected static NotificationEntry createEntry(int id, Notification n) {
+ return new NotificationEntryBuilder().setSbn(createSbn(id, n)).build();
+ }
+
+ protected static NotificationEntry createEntry(int id, Context context) {
+ return new NotificationEntryBuilder().setSbn(
+ HeadsUpManagerTestUtil.createSbn(id, context)).build();
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
new file mode 100644
index 0000000..2747629
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
+import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.graphics.Region;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.time.SystemClock;
+
+class TestableHeadsUpManager extends BaseHeadsUpManager {
+
+ private HeadsUpEntry mLastCreatedEntry;
+
+ TestableHeadsUpManager(Context context,
+ HeadsUpManagerLogger logger,
+ DelayableExecutor executor,
+ GlobalSettings globalSettings,
+ SystemClock systemClock,
+ AccessibilityManagerWrapper accessibilityManagerWrapper,
+ UiEventLogger uiEventLogger) {
+ super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock,
+ executor, accessibilityManagerWrapper, uiEventLogger);
+
+ mTouchAcceptanceDelay = BaseHeadsUpManagerTest.TEST_TOUCH_ACCEPTANCE_TIME;
+ mMinimumDisplayTime = BaseHeadsUpManagerTest.TEST_MINIMUM_DISPLAY_TIME;
+ mAutoDismissTime = BaseHeadsUpManagerTest.TEST_AUTO_DISMISS_TIME;
+ mStickyForSomeTimeAutoDismissTime = BaseHeadsUpManagerTest.TEST_STICKY_AUTO_DISMISS_TIME;
+ }
+
+ @Override
+ protected HeadsUpEntry createHeadsUpEntry() {
+ mLastCreatedEntry = spy(super.createHeadsUpEntry());
+ return mLastCreatedEntry;
+ }
+
+ @Override
+ public int getContentFlag() {
+ return FLAG_CONTENT_VIEW_CONTRACTED;
+ }
+
+ // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
+ @Override
+ public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addSwipedOutNotification(@NonNull String key) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void extendHeadsUp() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Nullable
+ @Override
+ public Region getTouchableRegion() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isHeadsUpGoingAway() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onExpandingFinished() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
+ boolean animate) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setRemoteInputActive(@NonNull NotificationEntry entry,
+ boolean remoteInputActive) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setTrackingHeadsUp(boolean tracking) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean shouldSwallowClick(@NonNull String key) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 10393cf..ca63483 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -196,7 +196,7 @@
final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback,
Handler resultCallbackHandler) {
boolean result = startRecentsActivity(intent, eventTime, animationHandler);
- if (resultCallback != null) {
+ if (resultCallback != null && resultCallbackHandler != null) {
resultCallbackHandler.post(new Runnable() {
@Override
public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
index 080dbed..93e2b37 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
@@ -21,6 +21,7 @@
import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_CONFIGURATION_OPTIONAL
import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE
import android.content.ComponentName
+import android.os.Bundle
import android.os.UserHandle
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
@@ -56,6 +57,7 @@
return widgetInfo.configure != null && !configurationOptional
}
}
+
private val logger = Logger(logBuffer, TAG)
/**
@@ -84,9 +86,16 @@
private fun bindWidget(widgetId: Int, user: UserHandle, provider: ComponentName): Boolean {
if (appWidgetManager.isPresent) {
+ val options =
+ Bundle().apply {
+ putInt(
+ AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+ AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
+ )
+ }
return appWidgetManager
.get()
- .bindAppWidgetIdIfAllowed(widgetId, user, provider, /* options */ null)
+ .bindAppWidgetIdIfAllowed(widgetId, user, provider, options)
}
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index 59288a1..0ea5390 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -41,7 +41,6 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onStart
@@ -111,7 +110,6 @@
awaitClose { clockRegistry.unregisterClockChangeListener(listener) }
}
.mapNotNull { it }
- .distinctUntilChanged()
override val currentClock: StateFlow<ClockController?> =
currentClockId
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index 873cc84..f46a207 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -22,6 +22,7 @@
import android.util.StateSet
import android.view.HapticFeedbackConstants
import android.view.View
+import androidx.core.view.isInvisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.common.ui.view.LongPressHandlingView
@@ -82,6 +83,11 @@
// of the transition.
repeatOnLifecycle(Lifecycle.State.CREATED) {
launch {
+ viewModel.isVisible.collect { isVisible ->
+ longPressHandlingView.isInvisible = !isVisible
+ }
+ }
+ launch {
viewModel.isLongPressEnabled.collect { isEnabled ->
longPressHandlingView.setLongPressHandlingEnabled(isEnabled)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index d657c24d..6281097 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -33,6 +33,7 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
@@ -70,12 +71,13 @@
// While dozing, the display can show the AOD UI; show the AOD udfps when dozing
private val useAodIconVariant: Flow<Boolean> =
- combine(isShowingAodOrDozing, deviceEntryUdfpsInteractor.isUdfpsSupported) {
- isTransitionToAodOrDozing,
- isUdfps ->
- isTransitionToAodOrDozing && isUdfps
+ deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfspEnrolled ->
+ if (udfspEnrolled) {
+ isShowingAodOrDozing.distinctUntilChanged()
+ } else {
+ flowOf(false)
}
- .distinctUntilChanged()
+ }
private val padding: Flow<Int> =
deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { udfpsSupported ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index c9cf0c3..31e8093 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -37,6 +37,7 @@
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
@@ -206,6 +207,7 @@
DeviceEntryIconView.IconType.LOCK
}
}
+ val isVisible: Flow<Boolean> = deviceEntryViewAlpha.map { it > 0f }.distinctUntilChanged()
val isLongPressEnabled: Flow<Boolean> =
combine(
iconType,
@@ -217,6 +219,7 @@
DeviceEntryIconView.IconType.FINGERPRINT -> false
}
}
+
val accessibilityDelegateHint: Flow<DeviceEntryIconView.AccessibilityHintType> =
combine(iconType, isLongPressEnabled) { deviceEntryStatus, longPressEnabled ->
if (longPressEnabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 7068f5f..d5bbaa5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1539,6 +1539,7 @@
@Override
public void setOpenCloseListener(OpenCloseListener openCloseListener) {
+ SceneContainerFlag.assertInLegacyMode();
mOpenCloseListener = openCloseListener;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index ea41912..e6555f2e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -32,6 +32,7 @@
import com.android.systemui.log.dagger.ShadeTouchLog;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
@@ -98,6 +99,7 @@
statusBarKeyguardViewManager,
notificationShadeWindowController,
assistManagerLazy);
+ SceneContainerFlag.assertInLegacyMode();
mCommandQueue = commandQueue;
mMainExecutor = mainExecutor;
mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index b07ba3c..a155e94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -67,7 +67,7 @@
private static final String TAG = "HeadsUpManagerPhone";
@VisibleForTesting
- final int mExtensionTime;
+ public final int mExtensionTime;
private final KeyguardBypassController mBypassController;
private final GroupMembershipManager mGroupMembershipManager;
private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 5a8b636..d975009 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -22,6 +22,7 @@
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.AlarmManager.AlarmClockInfo;
+import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -379,7 +380,7 @@
}
@Override
- public void onConfigChanged(ZenModeConfig config) {
+ public void onConsolidatedPolicyChanged(NotificationManager.Policy policy) {
updateVolumeZen();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
index e97edcb..9b8cf59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
@@ -27,7 +27,7 @@
import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
@@ -39,6 +39,7 @@
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.runner.RunWith
@@ -52,7 +53,7 @@
}
private val deviceEntryIconTransition = kosmos.fakeDeviceEntryIconViewModelTransition
private val testScope = kosmos.testScope
- private val keyguardRepository = kosmos.fakeKeyguardRepository
+ private val biometricSettingsRepository = kosmos.fakeBiometricSettingsRepository
private val accessibilityRepository = kosmos.fakeAccessibilityRepository
private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
@@ -85,22 +86,12 @@
setupVisibleStateOnLockscreen()
// AOD
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.AOD,
- value = 0f,
- transitionState = TransitionState.STARTED,
- )
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.AOD,
+ this,
)
- keyguardTransitionRepository.sendTransitionStep(
- TransitionStep(
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.AOD,
- value = 1f,
- transitionState = TransitionState.FINISHED,
- )
- )
+ runCurrent()
assertThat(visible).isFalse()
}
fun fpNotRunning_overlayNotVisible() =
@@ -129,6 +120,7 @@
// Listening for UDFPS
fingerprintPropertyRepository.supportsUdfps()
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
deviceEntryFingerprintAuthRepository.setIsRunning(true)
deviceEntryRepository.setUnlocked(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
new file mode 100644
index 0000000..02bd810
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceEntryIconViewModelTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private lateinit var keyguardRepository: FakeKeyguardRepository
+ private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+ private lateinit var fingerprintAuthRepository: FakeDeviceEntryFingerprintAuthRepository
+ private lateinit var deviceEntryIconTransition: FakeDeviceEntryIconTransition
+ private lateinit var underTest: DeviceEntryIconViewModel
+
+ @Before
+ fun setUp() {
+ keyguardRepository = kosmos.fakeKeyguardRepository
+ fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+ fingerprintAuthRepository = kosmos.fakeDeviceEntryFingerprintAuthRepository
+ deviceEntryIconTransition = kosmos.fakeDeviceEntryIconViewModelTransition
+ underTest = kosmos.deviceEntryIconViewModel
+ }
+
+ @Test
+ fun isLongPressEnabled_udfpsRunning() =
+ testScope.runTest {
+ val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+ fingerprintPropertyRepository.supportsUdfps()
+ fingerprintAuthRepository.setIsRunning(true)
+ keyguardRepository.setKeyguardDismissible(false)
+ assertThat(isLongPressEnabled).isFalse()
+ }
+
+ @Test
+ fun isLongPressEnabled_unlocked() =
+ testScope.runTest {
+ val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+ keyguardRepository.setKeyguardDismissible(true)
+ assertThat(isLongPressEnabled).isTrue()
+ }
+
+ @Test
+ fun isLongPressEnabled_lock() =
+ testScope.runTest {
+ val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+ keyguardRepository.setKeyguardDismissible(false)
+
+ // udfps supported
+ fingerprintPropertyRepository.supportsUdfps()
+ assertThat(isLongPressEnabled).isTrue()
+
+ // udfps isn't supported
+ fingerprintPropertyRepository.supportsRearFps()
+ assertThat(isLongPressEnabled).isFalse()
+ }
+
+ @Test
+ fun isVisible() =
+ testScope.runTest {
+ val isVisible by collectLastValue(underTest.isVisible)
+ deviceEntryIconTransitionAlpha(1f)
+ assertThat(isVisible).isTrue()
+
+ deviceEntryIconTransitionAlpha(0f)
+ assertThat(isVisible).isFalse()
+
+ deviceEntryIconTransitionAlpha(.5f)
+ assertThat(isVisible).isTrue()
+ }
+
+ private fun deviceEntryIconTransitionAlpha(alpha: Float) {
+ deviceEntryIconTransition.setDeviceEntryParentViewAlpha(alpha)
+ }
+}
diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java
index 4a2f3da..e9f6031 100644
--- a/rs/java/android/renderscript/ScriptC.java
+++ b/rs/java/android/renderscript/ScriptC.java
@@ -38,12 +38,12 @@
private static final String TAG = "ScriptC";
/**
- * In targetSdkVersion 35 and above, Renderscript's ScriptC stops being supported
+ * In targetSdkVersion 36 and above, Renderscript's ScriptC stops being supported
* and an exception is thrown when the class is instantiated.
- * In targetSdkVersion 34 and below, Renderscript's ScriptC still works.
+ * In targetSdkVersion 35 and below, Renderscript's ScriptC still works.
*/
@ChangeId
- @EnabledAfter(targetSdkVersion = 35)
+ @EnabledAfter(targetSdkVersion = 36)
private static final long RENDERSCRIPT_SCRIPTC_DEPRECATION_CHANGE_ID = 297019750L;
/**
@@ -113,9 +113,9 @@
throw new UnsupportedOperationException(s);
}
- // Throw an exception if the target API is 35 or above
+ // Throw an exception if the target API is 36 or above
String message =
- "ScriptC scripts are not supported when targeting an API Level >= 35. Please refer "
+ "ScriptC scripts are not supported when targeting an API Level >= 36. Please refer "
+ "to https://developer.android.com/guide/topics/renderscript/migration-guide "
+ "for proposed alternatives.";
Slog.w(TAG, message);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index c7b844b..d779fbf 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -193,7 +193,6 @@
import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.PrintWriter;
-import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
@@ -2821,8 +2820,9 @@
mSessionFlags.mExpiredResponse = false;
final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
- final Serializable exception = data.getSerializable(
- CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION);
+ final GetCredentialException exception = data.getSerializable(
+ CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
+ GetCredentialException.class);
final Bundle newClientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE);
if (sDebug) {
@@ -5126,6 +5126,10 @@
toIpcFriendlyResultReceiver(resultReceiver);
Intent metadataIntent = dataset.getCredentialFillInIntent();
+ if (metadataIntent == null) {
+ metadataIntent = new Intent();
+ }
+
metadataIntent.putExtra(
android.credentials.selection.Constants.EXTRA_FINAL_RESPONSE_RECEIVER,
ipcFriendlyResultReceiver);
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 0cc6494..fb62785 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -661,8 +661,12 @@
@NonNull OpEntry createEntryLocked(String persistentDeviceId) {
// TODO(b/308201969): Update this method when we introduce disk persistence of events
// for accesses on external devices.
- final ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
+ ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
persistentDeviceId);
+ if (attributedOps == null) {
+ attributedOps = new ArrayMap<>();
+ }
+
final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries =
new ArrayMap<>(attributedOps.size());
for (int i = 0; i < attributedOps.size(); i++) {
@@ -680,8 +684,12 @@
@NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) {
// TODO(b/308201969): Update this method when we introduce disk persistence of events
// for accesses on external devices.
- final ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
+ ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
PERSISTENT_DEVICE_ID_DEFAULT);
+ if (attributedOps == null) {
+ attributedOps = new ArrayMap<>();
+ }
+
final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1);
if (attributedOps.get(attributionTag) != null) {
attributionEntries.put(attributionTag,
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 8cc242c..5bd8ca6 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -17,6 +17,8 @@
package com.android.server.pm;
import static android.content.pm.Flags.disallowSdkLibsToBeApps;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_INSTALLER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
@@ -43,11 +45,11 @@
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.APP_METADATA_FILE_NAME;
import static com.android.server.pm.DexOptHelper.useArtService;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
-import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_NAME;
import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
@@ -2225,10 +2227,16 @@
if (appMetadataFile.exists()) {
ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
if (Flags.aslInApkAppMetadataSource()) {
- ps.setAppMetadataSource(PackageManager.APP_METADATA_SOURCE_INSTALLER);
+ ps.setAppMetadataSource(APP_METADATA_SOURCE_INSTALLER);
}
} else {
- ps.setAppMetadataFilePath(null);
+ if (Flags.aslInApkAppMetadataSource()
+ && parsedPackage.isAppMetadataFileInApk()) {
+ ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
+ ps.setAppMetadataSource(APP_METADATA_SOURCE_APK);
+ } else {
+ ps.setAppMetadataFilePath(null);
+ }
}
}
if (installRequest.getReturnCode() == PackageManager.INSTALL_SUCCEEDED) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5792d86..ba90378 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -358,7 +358,7 @@
/** Default byte size limit for app metadata */
private static final long DEFAULT_APP_METADATA_BYTE_SIZE_LIMIT = 32000;
- private static final int APP_METADATA_FILE_ACCESS_MODE = 0640;
+ static final int APP_METADATA_FILE_ACCESS_MODE = 0640;
/**
* Throws IllegalArgumentException if the {@link IntentSender} from an immutable
@@ -964,7 +964,7 @@
private boolean isEmergencyInstallerEnabled(String packageName, Computer snapshot) {
final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
- if (ps == null || ps.getPkg() == null || !ps.isSystem()) {
+ if (ps == null || ps.getPkg() == null) {
return false;
}
String emergencyInstaller = ps.getPkg().getEmergencyInstaller();
@@ -1782,8 +1782,7 @@
}
private File getStagedAppMetadataFile() {
- File file = new File(stageDir, APP_METADATA_FILE_NAME);
- return file.exists() ? file : null;
+ return new File(stageDir, APP_METADATA_FILE_NAME);
}
private static boolean isAppMetadata(String name) {
@@ -1799,7 +1798,7 @@
assertCallerIsOwnerOrRoot();
synchronized (mLock) {
assertPreparedAndNotCommittedOrDestroyedLocked("getAppMetadataFd");
- if (getStagedAppMetadataFile() == null) {
+ if (!getStagedAppMetadataFile().exists()) {
return null;
}
try {
@@ -1813,12 +1812,12 @@
@Override
public void removeAppMetadata() {
File file = getStagedAppMetadataFile();
- if (file != null) {
+ if (file.exists()) {
file.delete();
}
}
- private static long getAppMetadataSizeLimit() {
+ static long getAppMetadataSizeLimit() {
final long token = Binder.clearCallingIdentity();
try {
return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE,
@@ -2131,7 +2130,7 @@
}
File appMetadataFile = getStagedAppMetadataFile();
- if (appMetadataFile != null) {
+ if (appMetadataFile.exists()) {
long sizeLimit = getAppMetadataSizeLimit();
if (appMetadataFile.length() > sizeLimit) {
appMetadataFile.delete();
@@ -3419,7 +3418,7 @@
final List<ApkLite> addedFiles = getAddedApkLitesLocked();
if (addedFiles.isEmpty()
- && (removeSplitList.size() == 0 || getStagedAppMetadataFile() != null)) {
+ && (removeSplitList.size() == 0 || getStagedAppMetadataFile().exists())) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
TextUtils.formatSimple("Session: %d. No packages staged in %s", sessionId,
stageDir.getAbsolutePath()));
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3c256b1..69f7906 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18,6 +18,8 @@
import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_UNKNOWN;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
@@ -596,7 +598,8 @@
static final String RANDOM_DIR_PREFIX = "~~";
static final char RANDOM_CODEPATH_PREFIX = '-';
- static final String APP_METADATA_FILE_NAME = "app.metadata";
+ public static final String APP_METADATA_FILE_NAME = "app.metadata";
+ public static final String APP_METADATA_FILE_IN_APK_PATH = "assets/" + APP_METADATA_FILE_NAME;
static final int DEFAULT_FILE_ACCESS_MODE = 0644;
@@ -5227,15 +5230,30 @@
new PackageManager.NameNotFoundException(packageName));
}
String filePath = ps.getAppMetadataFilePath();
- if (filePath != null) {
- File file = new File(filePath);
- try {
- return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
- } catch (FileNotFoundException e) {
+ if (filePath == null) {
+ return null;
+ }
+ File file = new File(filePath);
+ if (Flags.aslInApkAppMetadataSource() && !file.exists()
+ && ps.getAppMetadataSource() == APP_METADATA_SOURCE_APK) {
+ String apkPath = ps.getPkg().getSplits().get(0).getPath();
+ if (!PackageManagerServiceUtils.extractAppMetadataFromApk(apkPath, file)) {
+ if (file.exists()) {
+ file.delete();
+ }
+ synchronized (mLock) {
+ PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
+ pkgSetting.setAppMetadataFilePath(null);
+ pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_UNKNOWN);
+ }
return null;
}
}
- return null;
+ try {
+ return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
}
@android.annotation.EnforcePermission(android.Manifest.permission.GET_APP_METADATA)
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 0a3dfc0..189a138 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -27,6 +27,9 @@
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH;
import static com.android.server.LocalManagerRegistry.ManagerNotFoundException;
+import static com.android.server.pm.PackageInstallerSession.APP_METADATA_FILE_ACCESS_MODE;
+import static com.android.server.pm.PackageInstallerSession.getAppMetadataSizeLimit;
+import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_IN_APK_PATH;
import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING;
@@ -142,6 +145,8 @@
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
/**
* Class containing helper methods for the PackageManagerService.
@@ -1559,6 +1564,35 @@
return initiatingPackageName == null || SHELL_PACKAGE_NAME.equals(initiatingPackageName);
}
+ /**
+ * Extract the app.metadata file from apk.
+ */
+ public static boolean extractAppMetadataFromApk(String apkPath, File appMetadataFile) {
+ boolean found = false;
+ try (ZipInputStream zipInputStream =
+ new ZipInputStream(new FileInputStream(new File(apkPath)))) {
+ ZipEntry zipEntry = null;
+ while ((zipEntry = zipInputStream.getNextEntry()) != null) {
+ if (zipEntry.getName().equals(APP_METADATA_FILE_IN_APK_PATH)) {
+ found = true;
+ try (FileOutputStream out = new FileOutputStream(appMetadataFile)) {
+ FileUtils.copy(zipInputStream, out);
+ }
+ if (appMetadataFile.length() > getAppMetadataSizeLimit()) {
+ appMetadataFile.delete();
+ return false;
+ }
+ Os.chmod(appMetadataFile.getAbsolutePath(), APP_METADATA_FILE_ACCESS_MODE);
+ break;
+ }
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, e.getMessage());
+ return false;
+ }
+ return found;
+ }
+
public static void linkFilesToOldDirs(@NonNull Installer installer,
@NonNull String packageName,
@NonNull File newPath,
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index f15646f..98499417 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -237,7 +237,7 @@
mAppOpsCallback = new IAppOpsCallback.Stub() {
public void opChanged(int op, int uid, @Nullable String packageName,
String persistentDeviceId) {
- if (Objects.equals(persistentDeviceId,
+ if (!Objects.equals(persistentDeviceId,
VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)) {
return;
}
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index b68e67e..34ea4ac 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -18,6 +18,7 @@
import static android.view.View.DRAG_FLAG_GLOBAL;
import static android.view.View.DRAG_FLAG_GLOBAL_SAME_APPLICATION;
+import static android.view.View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG;
import static com.android.input.flags.Flags.enablePointerChoreographer;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
@@ -373,8 +374,11 @@
boolean notifyUnhandledDrop(DragEvent dropEvent, String reason) {
final boolean isLocalDrag =
(mDragState.mFlags & (DRAG_FLAG_GLOBAL_SAME_APPLICATION | DRAG_FLAG_GLOBAL)) == 0;
+ final boolean shouldDelegateUnhandledDrag =
+ (mDragState.mFlags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0;
if (!com.android.window.flags.Flags.delegateUnhandledDrags()
|| mGlobalDragListener == null
+ || !shouldDelegateUnhandledDrag
|| isLocalDrag) {
// Skip if the flag is disabled, there is no unhandled-drag listener, or if this is a
// purely local drag
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index 9d45cfb..027337f 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -18,7 +18,6 @@
import static android.credentials.selection.Constants.EXTRA_FINAL_RESPONSE_RECEIVER;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -161,26 +160,6 @@
*/
public PendingIntent createPendingIntent(
RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) {
- return createPendingIntent(requestInfo, providerDataList, /*forAutofill=*/ false);
- }
-
- /**
- * Creates a {@link PendingIntent} to be used to invoke the credential manager selector UI,
- * by the calling app process. This intent is invoked from the Autofill flow, when the user
- * requests to bring up the 'All Options' page of the credential bottom-sheet. When the user
- * clicks on the pinned entry, the intent will bring up the 'All Options' page of the
- * bottom-sheet. The provider data list is processed by the credential autofill service for
- * each autofill id and passed in as an auth extra.
- *
- * @param requestInfo the information about the request
- */
- public PendingIntent createPendingIntentForAutofill(RequestInfo requestInfo) {
- return createPendingIntent(requestInfo, /*providerDataList=*/ null, /*forAutofill=*/ true);
- }
-
- private PendingIntent createPendingIntent(
- RequestInfo requestInfo, @Nullable ArrayList<ProviderData> providerDataList,
- boolean forAutofill) {
List<CredentialProviderInfo> allProviders =
CredentialProviderInfoFactory.getCredentialProviderServices(
mContext,
@@ -196,15 +175,9 @@
disabledProvider.getComponentName().flattenToString())).toList();
Intent intent;
- if (forAutofill) {
- intent = IntentFactory.createCredentialSelectorIntentForAutofill(
- mContext, requestInfo, new ArrayList<>(disabledProviderDataList),
- mResultReceiver);
- } else {
- intent = IntentFactory.createCredentialSelectorIntent(
- mContext, requestInfo, providerDataList,
- new ArrayList<>(disabledProviderDataList), mResultReceiver);
- }
+ intent = IntentFactory.createCredentialSelectorIntent(
+ mContext, requestInfo, providerDataList,
+ new ArrayList<>(disabledProviderDataList), mResultReceiver);
intent.setAction(UUID.randomUUID().toString());
//TODO: Create unique pending intent using request code and cancel any pre-existing pending
// intents
@@ -213,4 +186,21 @@
PendingIntent.FLAG_MUTABLE, /*options=*/null,
UserHandle.of(mUserId));
}
+
+ /**
+ * Creates an {@link Intent} to be used to invoke the credential manager selector UI,
+ * by the calling app process. This intent is invoked from the Autofill flow, when the user
+ * requests to bring up the 'All Options' page of the credential bottom-sheet. When the user
+ * clicks on the pinned entry, the intent will bring up the 'All Options' page of the
+ * bottom-sheet. The provider data list is processed by the credential autofill service for
+ * each autofill id and passed in as extras in the pending intent set as authentication
+ * of the pinned entry.
+ *
+ * @param requestInfo the information about the request
+ */
+ public Intent createIntentForAutofill(RequestInfo requestInfo) {
+ return IntentFactory.createCredentialSelectorIntentForAutofill(
+ mContext, requestInfo, new ArrayList<>(),
+ mResultReceiver);
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
index ca72638..3cb98eb 100644
--- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.credentials.Constants;
import android.credentials.CredentialProviderInfo;
import android.credentials.GetCandidateCredentialsException;
@@ -114,8 +115,7 @@
return;
}
- cancelExistingPendingIntent();
- mPendingIntent = mCredentialManagerUi.createPendingIntentForAutofill(
+ Intent intent = mCredentialManagerUi.createIntentForAutofill(
RequestInfo.newGetRequestInfo(
mRequestId, mClientRequest, mClientAppInfo.getPackageName(),
PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(),
@@ -129,7 +129,7 @@
try {
invokeClientCallbackSuccess(new GetCandidateCredentialsResponse(
- candidateProviderDataList, mPendingIntent));
+ candidateProviderDataList, intent));
} catch (RemoteException e) {
Slog.e(TAG, "Issue while responding to client with error : " + e);
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index fa63bc8..cad9a09 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -93,7 +93,7 @@
android.credentials.GetCredentialRequest filteredRequest =
filterOptions(providerInfo.getCapabilities(),
getRequestSession.mClientRequest,
- providerInfo);
+ providerInfo, getRequestSession.mHybridService);
if (filteredRequest != null) {
Map<String, CredentialOption> beginGetOptionToCredentialOptionMap =
new HashMap<>();
@@ -129,7 +129,7 @@
android.credentials.GetCredentialRequest filteredRequest =
filterOptions(providerInfo.getCapabilities(),
getRequestSession.mClientRequest,
- providerInfo);
+ providerInfo, getRequestSession.mHybridService);
if (filteredRequest != null) {
Map<String, CredentialOption> beginGetOptionToCredentialOptionMap =
new HashMap<>();
@@ -179,9 +179,19 @@
private static android.credentials.GetCredentialRequest filterOptions(
List<String> providerCapabilities,
android.credentials.GetCredentialRequest clientRequest,
- CredentialProviderInfo info
- ) {
+ CredentialProviderInfo info,
+ String hybridService) {
Slog.i(TAG, "Filtering request options for: " + info.getComponentName());
+ if (android.credentials.flags.Flags.hybridFilterFixEnabled()) {
+ ComponentName hybridComponentName = ComponentName.unflattenFromString(hybridService);
+ if (hybridComponentName != null && hybridComponentName
+ .equals(info.getComponentName())) {
+ Slog.i(TAG, "Skipping filtering of options for hybrid service");
+ return clientRequest;
+ }
+ Slog.w(TAG, "Could not parse hybrid service while filtering options");
+ }
+
List<CredentialOption> filteredOptions = new ArrayList<>();
for (CredentialOption option : clientRequest.getCredentialOptions()) {
if (providerCapabilities.contains(option.getType())
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
index df7f308..1000bfa 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
@@ -53,7 +53,17 @@
TelephonyManager telephonyService = context.getSystemService(TelephonyManager.class);
Preconditions.checkState(telephonyService != null, "Unable to access telephony service");
mImei = telephonyService.getImei(0);
- mMeid = telephonyService.getMeid(0);
+ String meid;
+ try {
+ meid = telephonyService.getMeid(0);
+ } catch (UnsupportedOperationException doesNotSupportCdma) {
+ // Instead of catching the exception, we could check for FEATURE_TELEPHONY_CDMA.
+ // However that runs the risk of changing a device's existing ESID if on these devices
+ // telephonyService.getMeid() actually returns non-null even when the device does not
+ // declare FEATURE_TELEPHONY_CDMA.
+ meid = null;
+ }
+ mMeid = meid;
mSerialNumber = Build.getSerial();
WifiManager wifiManager = context.getSystemService(WifiManager.class);
Preconditions.checkState(wifiManager != null, "Unable to access WiFi service");
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index d4b57f1..96e9ca0 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -275,6 +275,7 @@
AndroidPackage::isUpdatableSystem,
AndroidPackage::getEmergencyInstaller,
AndroidPackage::isAllowCrossUidActivitySwitchFromBelow,
+ PackageImpl::isAppMetadataFileInApk,
)
override fun extraParams() = listOf(
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
index d6e246f..6e41685 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
@@ -25,6 +25,8 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -42,6 +44,7 @@
import android.crashrecovery.flags.Flags;
import android.os.Handler;
import android.os.MessageQueue;
+import android.os.SystemProperties;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.runner.AndroidJUnit4;
@@ -65,6 +68,7 @@
import org.mockito.stubbing.Answer;
import java.time.Duration;
+import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -90,7 +94,7 @@
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
+ private HashMap<String, String> mSystemSettingsMap;
private MockitoSession mSession;
private static final String APP_A = "com.package.a";
private static final String APP_B = "com.package.b";
@@ -99,6 +103,9 @@
private static final long VERSION_CODE_2 = 2L;
private static final String LOG_TAG = "RollbackPackageHealthObserverTest";
+ private static final String PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG =
+ "persist.device_config.configuration.disable_high_impact_rollback";
+
private SystemConfig mSysConfig;
@Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
@@ -111,11 +118,34 @@
.initMocks(this)
.strictness(Strictness.LENIENT)
.spyStatic(PackageWatchdog.class)
+ .spyStatic(SystemProperties.class)
.startMocking();
+ mSystemSettingsMap = new HashMap<>();
// Mock PackageWatchdog
doAnswer((Answer<PackageWatchdog>) invocationOnMock -> mMockPackageWatchdog)
.when(() -> PackageWatchdog.getInstance(mMockContext));
+
+ // Mock SystemProperties setter and various getters
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+ String value = invocationOnMock.getArgument(1);
+
+ mSystemSettingsMap.put(key, value);
+ return null;
+ }
+ ).when(() -> SystemProperties.set(anyString(), anyString()));
+
+ doAnswer((Answer<Boolean>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+ boolean defaultValue = invocationOnMock.getArgument(1);
+
+ String storedValue = mSystemSettingsMap.get(key);
+ return storedValue == null ? defaultValue : Boolean.parseBoolean(storedValue);
+ }
+ ).when(() -> SystemProperties.getBoolean(anyString(), anyBoolean()));
+
+ SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(false));
}
@After
@@ -609,6 +639,32 @@
observer.onBootLoop(1));
}
+ @Test
+ public void onBootLoop_impactLevelHighDisableHighImpactRollback_onePackage()
+ throws PackageManager.NameNotFoundException {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true));
+ VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2);
+ VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE);
+ PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo,
+ null, null, false, false,
+ null);
+ RollbackInfo rollbackInfo1 = new RollbackInfo(1, List.of(packageRollbackInfo),
+ false, null, 111,
+ PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+ RollbackPackageHealthObserver observer =
+ spy(new RollbackPackageHealthObserver(mMockContext, mApexManager));
+
+ when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+ // Make the rollbacks available
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(rollbackInfo1));
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockPackageManager.getModuleInfo(any(), eq(0))).thenReturn(null);
+
+ assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
+ observer.onBootLoop(1));
+ }
+
/**
* When the rollback impact level is manual only return user impact level 0. (User impact level
* 0 is ignored by package watchdog)
@@ -924,6 +980,50 @@
assertThat(argument.getAllValues()).isEqualTo(List.of(rollbackId2));
}
+ /**
+ * Don't roll back if kill switch is enabled.
+ */
+ @Test
+ public void executeBootLoopMitigation_impactLevelHighKillSwitchTrue_rollbackHigh()
+ throws PackageManager.NameNotFoundException {
+ mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true));
+ int rollbackId1 = 1;
+ VersionedPackage appBFrom = new VersionedPackage(APP_B, VERSION_CODE_2);
+ VersionedPackage appBTo = new VersionedPackage(APP_B, VERSION_CODE);
+ PackageRollbackInfo packageRollbackInfoB = new PackageRollbackInfo(appBFrom, appBTo,
+ null, null , false, false,
+ null);
+ RollbackInfo rollbackInfo1 = new RollbackInfo(rollbackId1, List.of(packageRollbackInfoB),
+ false, null, 111,
+ PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+ int rollbackId2 = 2;
+ VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2);
+ VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE);
+ PackageRollbackInfo packageRollbackInfoA = new PackageRollbackInfo(appAFrom, appATo,
+ null, null , false, false,
+ null);
+ RollbackInfo rollbackInfo2 = new RollbackInfo(rollbackId2, List.of(packageRollbackInfoA),
+ false, null, 111,
+ PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+ RollbackPackageHealthObserver observer =
+ spy(new RollbackPackageHealthObserver(mMockContext, mApexManager));
+ ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
+
+ when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+ // Make the rollbacks available
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(
+ List.of(rollbackInfo1, rollbackInfo2));
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockPackageManager.getModuleInfo(any(), eq(0))).thenReturn(null);
+
+ observer.executeBootLoopMitigation(1);
+ waitForIdleHandler(observer.getHandler(), Duration.ofSeconds(10));
+
+ verify(mRollbackManager, never()).commitRollback(
+ argument.capture(), any(), any());
+ }
+
private void waitForIdleHandler(Handler handler, Duration timeout) {
final MessageQueue queue = handler.getLooper().getQueue();
final CountDownLatch latch = new CountDownLatch(1);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 4c32a58..a0461a6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -42,6 +42,7 @@
import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -541,7 +542,7 @@
}
@Test
- public void testUnhandledDragListenerNotCalledForNormalDrags() throws RemoteException {
+ public void testUnhandledDragNotCalledForNormalDrags() throws RemoteException {
assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
final IGlobalDragListener listener = mock(IGlobalDragListener.class);
@@ -552,15 +553,16 @@
}
@Test
- public void testUnhandledDragListenerReceivesUnhandledDropOverWindow() {
+ public void testUnhandledDragReceivesUnhandledDropOverWindow() {
assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
final IGlobalDragListener listener = mock(IGlobalDragListener.class);
doReturn(mock(Binder.class)).when(listener).asBinder();
mTarget.setGlobalDragListener(listener);
final int invalidXY = 100_000;
- startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
- // Notify the unhandled drag listener
+ startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+ ClipData.newPlainText("label", "Test"), () -> {
+ // Trigger an unhandled drop and verify the global drag listener was called
mTarget.reportDropWindow(mWindow.mInputChannelToken, invalidXY, invalidXY);
mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
mTarget.reportDropResult(mWindow.mClient, false);
@@ -575,15 +577,16 @@
}
@Test
- public void testUnhandledDragListenerReceivesUnhandledDropOverNoValidWindow() {
+ public void testUnhandledDragReceivesUnhandledDropOverNoValidWindow() {
assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
final IGlobalDragListener listener = mock(IGlobalDragListener.class);
doReturn(mock(Binder.class)).when(listener).asBinder();
mTarget.setGlobalDragListener(listener);
final int invalidXY = 100_000;
- startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
- // Notify the unhandled drag listener
+ startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+ ClipData.newPlainText("label", "Test"), () -> {
+ // Trigger an unhandled drop and verify the global drag listener was called
mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
mTarget.onUnhandledDropCallback(true);
@@ -597,15 +600,38 @@
}
@Test
- public void testUnhandledDragListenerCallbackTimeout() {
+ public void testUnhandledDragDoesNotReceiveUnhandledDropWithoutDragFlag() {
assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
final IGlobalDragListener listener = mock(IGlobalDragListener.class);
doReturn(mock(Binder.class)).when(listener).asBinder();
mTarget.setGlobalDragListener(listener);
final int invalidXY = 100_000;
- startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
- // Notify the unhandled drag listener
+ startDrag(View.DRAG_FLAG_GLOBAL,
+ ClipData.newPlainText("label", "Test"), () -> {
+ // Trigger an unhandled drop and verify the global drag listener was not called
+ mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
+ mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
+ mToken = null;
+ try {
+ verify(listener, never()).onUnhandledDrop(any(), any());
+ } catch (RemoteException e) {
+ fail("Failed to verify unhandled drop: " + e);
+ }
+ });
+ }
+
+ @Test
+ public void testUnhandledDragCallbackTimeout() {
+ assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
+
+ final IGlobalDragListener listener = mock(IGlobalDragListener.class);
+ doReturn(mock(Binder.class)).when(listener).asBinder();
+ mTarget.setGlobalDragListener(listener);
+ final int invalidXY = 100_000;
+ startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+ ClipData.newPlainText("label", "Test"), () -> {
+ // Trigger an unhandled drop and verify the global drag listener was called
mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);