Merge "Modify usagestats event processing thread" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index b924ac8..c8046ab 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -152,6 +152,11 @@
java_aconfig_library {
name: "android.nfc.flags-aconfig-java",
aconfig_declarations: "android.nfc.flags-aconfig",
+ min_sdk_version: "VanillaIceCream",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.nfcservices",
+ ],
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
@@ -289,6 +294,12 @@
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+rust_aconfig_library {
+ name: "libandroid_security_flags_rust",
+ crate_name: "android_security_flags",
+ aconfig_declarations: "android.security.flags-aconfig",
+}
+
// Package Manager
aconfig_declarations {
name: "android.content.pm.flags-aconfig",
diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp
index 45bb161..e7adf20 100644
--- a/ProtoLibraries.bp
+++ b/ProtoLibraries.bp
@@ -77,6 +77,42 @@
output_extension: "proto.h",
}
+// ==== nfc framework java library ==============================
+gensrcs {
+ name: "framework-nfc-javastream-protos",
+
+ tools: [
+ "aprotoc",
+ "protoc-gen-javastream",
+ "soong_zip",
+ ],
+
+ cmd: "mkdir -p $(genDir)/$(in) " +
+ "&& $(location aprotoc) " +
+ " --plugin=$(location protoc-gen-javastream) " +
+ " --javastream_out=$(genDir)/$(in) " +
+ " -Iexternal/protobuf/src " +
+ " -I . " +
+ " $(in) " +
+ "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
+
+ srcs: [
+ "core/proto/android/app/pendingintent.proto",
+ "core/proto/android/content/component_name.proto",
+ "core/proto/android/content/intent.proto",
+ "core/proto/android/nfc/*.proto",
+ "core/proto/android/os/patternmatcher.proto",
+ "core/proto/android/os/persistablebundle.proto",
+ "core/proto/android/privacy.proto",
+ ],
+
+ data: [
+ ":libprotobuf-internal-protos",
+ ],
+
+ output_extension: "srcjar",
+}
+
// ==== java proto host library ==============================
java_library_host {
name: "platformprotos",
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index d48d84b..1fdf906 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -75,6 +75,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import java.util.regex.Pattern;
/**
* Maintains the master list of jobs that the job scheduler is tracking. These jobs are compared by
@@ -99,6 +100,8 @@
private static final long SCHEDULED_JOB_HIGH_WATER_MARK_PERIOD_MS = 30 * 60_000L;
@VisibleForTesting
static final String JOB_FILE_SPLIT_PREFIX = "jobs_";
+ private static final Pattern SPLIT_FILE_PATTERN =
+ Pattern.compile("^" + JOB_FILE_SPLIT_PREFIX + "\\d+.xml$");
private static final int ALL_UIDS = -1;
@VisibleForTesting
static final int INVALID_UID = -2;
@@ -1121,6 +1124,11 @@
int numDuplicates = 0;
synchronized (mLock) {
for (File file : files) {
+ if (!file.getName().equals("jobs.xml")
+ && !SPLIT_FILE_PATTERN.matcher(file.getName()).matches()) {
+ // Skip temporary or other files.
+ continue;
+ }
final AtomicFile aFile = createJobFile(file);
try (FileInputStream fis = aFile.openRead()) {
jobs = readJobMapImpl(fis, rtcGood, nowElapsed);
diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp
index e162100..e086bfe 100644
--- a/api/ApiDocs.bp
+++ b/api/ApiDocs.bp
@@ -139,9 +139,22 @@
// using droiddoc
/////////////////////////////////////////////////////////////////////
-framework_docs_only_args = " -android -manifest $(location :frameworks-base-core-AndroidManifest.xml) " +
+// doclava contains checks for a few issues that are have been migrated to metalava.
+// disable them in doclava, to avoid mistriggering or double triggering.
+ignore_doclava_errors_checked_by_metalava = "" +
+ "-hide 111 " + // HIDDEN_SUPERCLASS
+ "-hide 113 " + // DEPRECATION_MISMATCH
+ "-hide 125 " + // REQUIRES_PERMISSION
+ "-hide 126 " + // BROADCAST_BEHAVIOR
+ "-hide 127 " + // SDK_CONSTANT
+ "-hide 128 " // TODO
+
+framework_docs_only_args = "-android " +
+ "-manifest $(location :frameworks-base-core-AndroidManifest.xml) " +
"-metalavaApiSince " +
- "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
+ "-werror " +
+ "-lerror " +
+ ignore_doclava_errors_checked_by_metalava +
"-overview $(location :frameworks-base-java-overview) " +
// Federate Support Library references against local API file.
"-federate SupportLib https://developer.android.com " +
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 7e41660..7e78185 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -739,7 +739,9 @@
"android_stubs_current_contributions",
"android_system_stubs_current_contributions",
"android_test_frameworks_core_stubs_current_contributions",
- "stub-annotation-defaults",
+ ],
+ libs: [
+ "stub-annotations",
],
api_contributions: [
"api-stubs-docs-non-updatable.api.contribution",
diff --git a/core/api/current.txt b/core/api/current.txt
index 51cdfc5..7d5417d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9533,6 +9533,7 @@
method public int getId();
method public int getSystemDataSyncFlags();
method @FlaggedApi("android.companion.association_tag") @Nullable public String getTag();
+ method public boolean isSelfManaged();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.companion.AssociationInfo> CREATOR;
}
@@ -23779,6 +23780,8 @@
field public static final int TYPE_DOCK = 13; // 0xd
field public static final int TYPE_GROUP = 2000; // 0x7d0
field public static final int TYPE_HDMI = 9; // 0x9
+ field @FlaggedApi("com.android.media.flags.enable_audio_policies_device_and_bluetooth_controller") public static final int TYPE_HDMI_ARC = 10; // 0xa
+ field @FlaggedApi("com.android.media.flags.enable_audio_policies_device_and_bluetooth_controller") public static final int TYPE_HDMI_EARC = 29; // 0x1d
field public static final int TYPE_HEARING_AID = 23; // 0x17
field public static final int TYPE_REMOTE_AUDIO_VIDEO_RECEIVER = 1003; // 0x3eb
field public static final int TYPE_REMOTE_CAR = 1008; // 0x3f0
@@ -45706,6 +45709,7 @@
field public static final int TYPE_IMS = 64; // 0x40
field public static final int TYPE_MCX = 1024; // 0x400
field public static final int TYPE_MMS = 2; // 0x2
+ field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int TYPE_RCS = 32768; // 0x8000
field public static final int TYPE_SUPL = 4; // 0x4
field public static final int TYPE_VSIM = 4096; // 0x1000
field public static final int TYPE_XCAP = 2048; // 0x800
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 70f5e2f..ac61107 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3149,7 +3149,6 @@
public final class AssociationInfo implements android.os.Parcelable {
method @NonNull public String getPackageName();
- method public boolean isSelfManaged();
}
public final class CompanionDeviceManager {
@@ -9641,6 +9640,7 @@
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setReaderMode(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff
@@ -10482,7 +10482,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public boolean isUserNameSet();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isUserOfType(@NonNull String);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isUserUnlockingOrUnlocked(@NonNull android.os.UserHandle);
- method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.MANAGE_USERS"}) public boolean isUserVisible();
+ method public boolean isUserVisible();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean removeUser(@NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public int removeUserWhenPossible(@NonNull android.os.UserHandle, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public void setBootUser(@NonNull android.os.UserHandle);
@@ -14717,6 +14717,7 @@
field public static final String TYPE_IMS_STRING = "ims";
field public static final String TYPE_MCX_STRING = "mcx";
field public static final String TYPE_MMS_STRING = "mms";
+ field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String TYPE_RCS_STRING = "rcs";
field public static final String TYPE_SUPL_STRING = "supl";
field public static final String TYPE_VSIM_STRING = "vsim";
field public static final String TYPE_XCAP_STRING = "xcap";
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 0293f66..ddb221f 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -14,6 +14,15 @@
hdrs: ["android/hardware/HardwareBuffer.aidl"],
}
+// TODO (b/303286040): Remove this once |ENABLE_NFC_MAINLINE_FLAG| is rolled out
+filegroup {
+ name: "framework-core-nfc-infcadapter-sources",
+ srcs: [
+ "android/nfc/INfcAdapter.aidl",
+ ],
+ visibility: ["//frameworks/base/services/core"],
+}
+
filegroup {
name: "framework-core-sources",
srcs: [
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index a3b82e9..d7d6546 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -161,12 +161,6 @@
*/
boolean isWallpaperBackupEligible(int which, int userId);
- /*
- * Keyguard: register a callback for being notified that lock-state relevant
- * wallpaper content has changed.
- */
- boolean setLockWallpaperCallback(IWallpaperManagerCallback cb);
-
/**
* Returns the colors used by the lock screen or system wallpaper.
*
@@ -253,13 +247,6 @@
boolean isStaticWallpaper(int which);
/**
- * Temporary method for project b/197814683.
- * Return true if the lockscreen wallpaper always uses a WallpaperService, not a static image.
- * @hide
- */
- boolean isLockscreenLiveWallpaperEnabled();
-
- /**
* Temporary method for project b/270726737.
* Return true if the wallpaper supports different crops for different display dimensions.
* @hide
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index e7a5b72..d660078 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -313,7 +313,6 @@
private final Context mContext;
private final boolean mWcgEnabled;
private final ColorManagementProxy mCmProxy;
- private static Boolean sIsLockscreenLiveWallpaperEnabled = null;
private static Boolean sIsMultiCropEnabled = null;
/**
@@ -841,29 +840,14 @@
}
/**
+ * TODO (b/305908217) remove
* Temporary method for project b/197814683.
* @return true if the lockscreen wallpaper always uses a wallpaperService, not a static image
* @hide
*/
@TestApi
public boolean isLockscreenLiveWallpaperEnabled() {
- return isLockscreenLiveWallpaperEnabledHelper();
- }
-
- private static boolean isLockscreenLiveWallpaperEnabledHelper() {
- if (sGlobals == null) {
- sIsLockscreenLiveWallpaperEnabled = SystemProperties.getBoolean(
- "persist.wm.debug.lockscreen_live_wallpaper", true);
- }
- if (sIsLockscreenLiveWallpaperEnabled == null) {
- try {
- sIsLockscreenLiveWallpaperEnabled =
- sGlobals.mService.isLockscreenLiveWallpaperEnabled();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- return sIsLockscreenLiveWallpaperEnabled;
+ return true;
}
/**
@@ -2446,12 +2430,7 @@
*/
@RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void clearWallpaper() {
- if (isLockscreenLiveWallpaperEnabled()) {
- clearWallpaper(FLAG_LOCK | FLAG_SYSTEM, mContext.getUserId());
- return;
- }
- clearWallpaper(FLAG_LOCK, mContext.getUserId());
- clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
+ clearWallpaper(FLAG_LOCK | FLAG_SYSTEM, mContext.getUserId());
}
/**
@@ -2787,11 +2766,7 @@
*/
@RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void clear() throws IOException {
- if (isLockscreenLiveWallpaperEnabled()) {
- clear(FLAG_SYSTEM | FLAG_LOCK);
- return;
- }
- setStream(openDefaultWallpaper(mContext, FLAG_SYSTEM), null, false);
+ clear(FLAG_SYSTEM | FLAG_LOCK);
}
/**
@@ -2816,16 +2791,7 @@
*/
@RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
public void clear(@SetWallpaperFlags int which) throws IOException {
- if (isLockscreenLiveWallpaperEnabled()) {
- clearWallpaper(which, mContext.getUserId());
- return;
- }
- if ((which & FLAG_SYSTEM) != 0) {
- clear();
- }
- if ((which & FLAG_LOCK) != 0) {
- clearWallpaper(FLAG_LOCK, mContext.getUserId());
- }
+ clearWallpaper(which, mContext.getUserId());
}
/**
@@ -2840,16 +2806,12 @@
public static InputStream openDefaultWallpaper(Context context, @SetWallpaperFlags int which) {
final String whichProp;
final int defaultResId;
- if (which == FLAG_LOCK && !isLockscreenLiveWallpaperEnabledHelper()) {
- /* Factory-default lock wallpapers are not yet supported
- whichProp = PROP_LOCK_WALLPAPER;
- defaultResId = com.android.internal.R.drawable.default_lock_wallpaper;
- */
- return null;
- } else {
- whichProp = PROP_WALLPAPER;
- defaultResId = com.android.internal.R.drawable.default_wallpaper;
- }
+ /* Factory-default lock wallpapers are not yet supported.
+ whichProp = which == FLAG_LOCK ? PROP_LOCK_WALLPAPER : PROP_WALLPAPER;
+ defaultResId = which == FLAG_LOCK ? R.drawable.default_lock_wallpaper : ....
+ */
+ whichProp = PROP_WALLPAPER;
+ defaultResId = R.drawable.default_wallpaper;
final String path = SystemProperties.get(whichProp);
final InputStream wallpaperInputStream = getWallpaperInputStream(path);
if (wallpaperInputStream != null) {
@@ -2988,25 +2950,6 @@
}
/**
- * Register a callback for lock wallpaper observation. Only the OS may use this.
- *
- * @return true on success; false on error.
- * @hide
- */
- public boolean setLockWallpaperCallback(IWallpaperManagerCallback callback) {
- if (sGlobals.mService == null) {
- Log.w(TAG, "WallpaperService not running");
- throw new RuntimeException(new DeadSystemException());
- }
-
- try {
- return sGlobals.mService.setLockWallpaperCallback(callback);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Is the current system wallpaper eligible for backup?
*
* Only the OS itself may use this method.
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index c145c02..f99615f 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -19,4 +19,11 @@
namespace: "enterprise"
description: "Add feature to track required changes for enabled V2 of auto-capturing of onboarding bug reports."
bug: "302517677"
-}
\ No newline at end of file
+}
+
+flag {
+ name: "cross_user_suspension_enabled"
+ namespace: "enterprise"
+ description: "Allow holders of INTERACT_ACROSS_USERS_FULL to suspend apps in different users."
+ bug: "263464464"
+}
diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
index 06bff5d..b34f678 100644
--- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java
+++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
@@ -58,11 +58,6 @@
super(in);
}
- @Override
- boolean isActivityLifecycleItem() {
- return true;
- }
-
/** A final lifecycle state that an activity should reach. */
@LifecycleState
public abstract int getTargetState();
diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
index f7f901b..8617386 100644
--- a/core/java/android/app/servertransaction/ClientTransaction.java
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -45,13 +45,6 @@
*/
public class ClientTransaction implements Parcelable, ObjectPoolItem {
- /**
- * List of transaction items that should be executed in order. Including both
- * {@link ActivityLifecycleItem} and other {@link ClientTransactionItem}.
- */
- @Nullable
- private List<ClientTransactionItem> mTransactionItems;
-
/** A list of individual callbacks to a client. */
@UnsupportedAppUsage
private List<ClientTransactionItem> mActivityCallbacks;
@@ -71,32 +64,9 @@
}
/**
- * Adds a message to the end of the sequence of transaction items.
- * @param item A single message that can contain a client activity/window request/callback.
- * TODO(b/260873529): replace both {@link #addCallback} and {@link #setLifecycleStateRequest}.
- */
- public void addTransactionItem(@NonNull ClientTransactionItem item) {
- if (mTransactionItems == null) {
- mTransactionItems = new ArrayList<>();
- }
- mTransactionItems.add(item);
- }
-
- /**
- * Gets the list of client window requests/callbacks.
- * TODO(b/260873529): must be non null after remove the deprecated methods.
- */
- @Nullable
- public List<ClientTransactionItem> getTransactionItems() {
- return mTransactionItems;
- }
-
- /**
- * Adds a message to the end of the sequence of callbacks.
+ * Add a message to the end of the sequence of callbacks.
* @param activityCallback A single message that can contain a lifecycle request/callback.
- * @deprecated use {@link #addTransactionItem(ClientTransactionItem)} instead.
*/
- @Deprecated
public void addCallback(@NonNull ClientTransactionItem activityCallback) {
if (mActivityCallbacks == null) {
mActivityCallbacks = new ArrayList<>();
@@ -104,35 +74,25 @@
mActivityCallbacks.add(activityCallback);
}
- /**
- * Gets the list of callbacks.
- * @deprecated use {@link #getTransactionItems()} instead.
- */
+ /** Get the list of callbacks. */
@Nullable
@VisibleForTesting
@UnsupportedAppUsage
- @Deprecated
public List<ClientTransactionItem> getCallbacks() {
return mActivityCallbacks;
}
- /**
- * Gets the target state lifecycle request.
- * @deprecated use {@link #getTransactionItems()} instead.
- */
+ /** Get the target state lifecycle request. */
@VisibleForTesting(visibility = PACKAGE)
@UnsupportedAppUsage
- @Deprecated
public ActivityLifecycleItem getLifecycleStateRequest() {
return mLifecycleStateRequest;
}
/**
- * Sets the lifecycle state in which the client should be after executing the transaction.
+ * Set the lifecycle state in which the client should be after executing the transaction.
* @param stateRequest A lifecycle request initialized with right parameters.
- * @deprecated use {@link #addTransactionItem(ClientTransactionItem)} instead.
*/
- @Deprecated
public void setLifecycleStateRequest(@NonNull ActivityLifecycleItem stateRequest) {
mLifecycleStateRequest = stateRequest;
}
@@ -143,14 +103,6 @@
* requested by transaction items.
*/
public void preExecute(@NonNull ClientTransactionHandler clientTransactionHandler) {
- if (mTransactionItems != null) {
- final int size = mTransactionItems.size();
- for (int i = 0; i < size; ++i) {
- mTransactionItems.get(i).preExecute(clientTransactionHandler);
- }
- return;
- }
-
if (mActivityCallbacks != null) {
final int size = mActivityCallbacks.size();
for (int i = 0; i < size; ++i) {
@@ -195,19 +147,12 @@
@Override
public void recycle() {
- if (mTransactionItems != null) {
- int size = mTransactionItems.size();
- for (int i = 0; i < size; i++) {
- mTransactionItems.get(i).recycle();
- }
- mTransactionItems = null;
- }
if (mActivityCallbacks != null) {
int size = mActivityCallbacks.size();
for (int i = 0; i < size; i++) {
mActivityCallbacks.get(i).recycle();
}
- mActivityCallbacks = null;
+ mActivityCallbacks.clear();
}
if (mLifecycleStateRequest != null) {
mLifecycleStateRequest.recycle();
@@ -220,15 +165,8 @@
// Parcelable implementation
/** Write to Parcel. */
- @SuppressWarnings("AndroidFrameworkEfficientParcelable") // Item class is not final.
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- final boolean writeTransactionItems = mTransactionItems != null;
- dest.writeBoolean(writeTransactionItems);
- if (writeTransactionItems) {
- dest.writeParcelableList(mTransactionItems, flags);
- }
-
dest.writeParcelable(mLifecycleStateRequest, flags);
final boolean writeActivityCallbacks = mActivityCallbacks != null;
dest.writeBoolean(writeActivityCallbacks);
@@ -239,20 +177,11 @@
/** Read from Parcel. */
private ClientTransaction(@NonNull Parcel in) {
- final boolean readTransactionItems = in.readBoolean();
- if (readTransactionItems) {
- mTransactionItems = new ArrayList<>();
- in.readParcelableList(mTransactionItems, getClass().getClassLoader(),
- ClientTransactionItem.class);
- }
-
- mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader(),
- ActivityLifecycleItem.class);
+ mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader(), android.app.servertransaction.ActivityLifecycleItem.class);
final boolean readActivityCallbacks = in.readBoolean();
if (readActivityCallbacks) {
mActivityCallbacks = new ArrayList<>();
- in.readParcelableList(mActivityCallbacks, getClass().getClassLoader(),
- ClientTransactionItem.class);
+ in.readParcelableList(mActivityCallbacks, getClass().getClassLoader(), android.app.servertransaction.ClientTransactionItem.class);
}
}
@@ -280,8 +209,7 @@
return false;
}
final ClientTransaction other = (ClientTransaction) o;
- return Objects.equals(mTransactionItems, other.mTransactionItems)
- && Objects.equals(mActivityCallbacks, other.mActivityCallbacks)
+ return Objects.equals(mActivityCallbacks, other.mActivityCallbacks)
&& Objects.equals(mLifecycleStateRequest, other.mLifecycleStateRequest)
&& mClient == other.mClient;
}
@@ -289,7 +217,6 @@
@Override
public int hashCode() {
int result = 17;
- result = 31 * result + Objects.hashCode(mTransactionItems);
result = 31 * result + Objects.hashCode(mActivityCallbacks);
result = 31 * result + Objects.hashCode(mLifecycleStateRequest);
result = 31 * result + Objects.hashCode(mClient);
@@ -300,22 +227,6 @@
void dump(@NonNull String prefix, @NonNull PrintWriter pw,
@NonNull ClientTransactionHandler transactionHandler) {
pw.append(prefix).println("ClientTransaction{");
- if (mTransactionItems != null) {
- pw.append(prefix).print(" transactionItems=[");
- final String itemPrefix = prefix + " ";
- final int size = mTransactionItems.size();
- if (size > 0) {
- pw.println();
- for (int i = 0; i < size; i++) {
- mTransactionItems.get(i).dump(itemPrefix, pw, transactionHandler);
- }
- pw.append(prefix).println(" ]");
- } else {
- pw.println("]");
- }
- pw.append(prefix).println("}");
- return;
- }
pw.append(prefix).print(" callbacks=[");
final String itemPrefix = prefix + " ";
final int size = mActivityCallbacks != null ? mActivityCallbacks.size() : 0;
diff --git a/core/java/android/app/servertransaction/ClientTransactionItem.java b/core/java/android/app/servertransaction/ClientTransactionItem.java
index f94e22d..07e5a7d 100644
--- a/core/java/android/app/servertransaction/ClientTransactionItem.java
+++ b/core/java/android/app/servertransaction/ClientTransactionItem.java
@@ -72,13 +72,6 @@
return null;
}
- /**
- * Whether this is a {@link ActivityLifecycleItem}.
- */
- boolean isActivityLifecycleItem() {
- return false;
- }
-
/** Dumps this transaction item. */
void dump(@NonNull String prefix, @NonNull PrintWriter pw,
@NonNull ClientTransactionHandler transactionHandler) {
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 9f5e0dc..066f9fe 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -28,7 +28,6 @@
import static android.app.servertransaction.TransactionExecutorHelper.getShortActivityName;
import static android.app.servertransaction.TransactionExecutorHelper.getStateName;
import static android.app.servertransaction.TransactionExecutorHelper.lastCallbackRequestingState;
-import static android.app.servertransaction.TransactionExecutorHelper.shouldExcludeLastLifecycleState;
import static android.app.servertransaction.TransactionExecutorHelper.tId;
import static android.app.servertransaction.TransactionExecutorHelper.transactionToString;
@@ -62,9 +61,6 @@
private final PendingTransactionActions mPendingActions = new PendingTransactionActions();
private final TransactionExecutorHelper mHelper = new TransactionExecutorHelper();
- /** Keeps track of display ids whose Configuration got updated within a transaction. */
- private final ArraySet<Integer> mConfigUpdatedDisplayIds = new ArraySet<>();
-
/** Initialize an instance with transaction handler, that will execute all requested actions. */
public TransactionExecutor(@NonNull ClientTransactionHandler clientTransactionHandler) {
mTransactionHandler = clientTransactionHandler;
@@ -83,52 +79,15 @@
Slog.d(TAG, transactionToString(transaction, mTransactionHandler));
}
- if (transaction.getTransactionItems() != null) {
- executeTransactionItems(transaction);
- } else {
- // TODO(b/260873529): cleanup after launch.
- executeCallbacks(transaction);
- executeLifecycleState(transaction);
- }
-
- if (!mConfigUpdatedDisplayIds.isEmpty()) {
- // Whether this transaction should trigger DisplayListener#onDisplayChanged.
- final ClientTransactionListenerController controller =
- ClientTransactionListenerController.getInstance();
- final int displayCount = mConfigUpdatedDisplayIds.size();
- for (int i = 0; i < displayCount; i++) {
- final int displayId = mConfigUpdatedDisplayIds.valueAt(i);
- controller.onDisplayChanged(displayId);
- }
- mConfigUpdatedDisplayIds.clear();
- }
+ executeCallbacks(transaction);
+ executeLifecycleState(transaction);
mPendingActions.clear();
if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
}
- /** Cycles through all transaction items and execute them at proper times. */
+ /** Cycle through all states requested by callbacks and execute them at proper times. */
@VisibleForTesting
- public void executeTransactionItems(@NonNull ClientTransaction transaction) {
- final List<ClientTransactionItem> items = transaction.getTransactionItems();
- final int size = items.size();
- for (int i = 0; i < size; i++) {
- final ClientTransactionItem item = items.get(i);
- if (item.isActivityLifecycleItem()) {
- executeLifecycleItem(transaction, (ActivityLifecycleItem) item);
- } else {
- executeNonLifecycleItem(transaction, item,
- shouldExcludeLastLifecycleState(items, i));
- }
- }
- }
-
- /**
- * Cycle through all states requested by callbacks and execute them at proper times.
- * @deprecated use {@link #executeTransactionItems} instead.
- */
- @VisibleForTesting
- @Deprecated
public void executeCallbacks(@NonNull ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
if (callbacks == null || callbacks.isEmpty()) {
@@ -146,78 +105,83 @@
// Index of the last callback that requests some post-execution state.
final int lastCallbackRequestingState = lastCallbackRequestingState(transaction);
+ // Keep track of display ids whose Configuration got updated with this transaction.
+ ArraySet<Integer> configUpdatedDisplays = null;
+
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
final ClientTransactionItem item = callbacks.get(i);
+ final IBinder token = item.getActivityToken();
+ ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
- // Skip the very last transition and perform it by explicit state request instead.
+ if (token != null && r == null
+ && mTransactionHandler.getActivitiesToBeDestroyed().containsKey(token)) {
+ // The activity has not been created but has been requested to destroy, so all
+ // transactions for the token are just like being cancelled.
+ Slog.w(TAG, "Skip pre-destroyed transaction item:\n" + item);
+ continue;
+ }
+
+ if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);
final int postExecutionState = item.getPostExecutionState();
- final boolean shouldExcludeLastLifecycleState = postExecutionState != UNDEFINED
- && i == lastCallbackRequestingState && finalState == postExecutionState;
- executeNonLifecycleItem(transaction, item, shouldExcludeLastLifecycleState);
- }
- }
- private void executeNonLifecycleItem(@NonNull ClientTransaction transaction,
- @NonNull ClientTransactionItem item, boolean shouldExcludeLastLifecycleState) {
- final IBinder token = item.getActivityToken();
- ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
+ if (item.shouldHaveDefinedPreExecutionState()) {
+ final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
+ item.getPostExecutionState());
+ if (closestPreExecutionState != UNDEFINED) {
+ cycleToPath(r, closestPreExecutionState, transaction);
+ }
+ }
- if (token != null && r == null
- && mTransactionHandler.getActivitiesToBeDestroyed().containsKey(token)) {
- // The activity has not been created but has been requested to destroy, so all
- // transactions for the token are just like being cancelled.
- Slog.w(TAG, "Skip pre-destroyed transaction item:\n" + item);
- return;
- }
+ // Can't read flag from isolated process.
+ final boolean isSyncWindowConfigUpdateFlagEnabled = !Process.isIsolated()
+ && syncWindowConfigUpdateFlag();
+ final Context configUpdatedContext = isSyncWindowConfigUpdateFlagEnabled
+ ? item.getContextToUpdate(mTransactionHandler)
+ : null;
+ final Configuration preExecutedConfig = configUpdatedContext != null
+ ? new Configuration(configUpdatedContext.getResources().getConfiguration())
+ : null;
- if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);
- final int postExecutionState = item.getPostExecutionState();
+ item.execute(mTransactionHandler, mPendingActions);
- if (item.shouldHaveDefinedPreExecutionState()) {
- final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
- postExecutionState);
- if (closestPreExecutionState != UNDEFINED) {
- cycleToPath(r, closestPreExecutionState, transaction);
+ if (configUpdatedContext != null) {
+ final Configuration postExecutedConfig = configUpdatedContext.getResources()
+ .getConfiguration();
+ if (!areConfigurationsEqualForDisplay(postExecutedConfig, preExecutedConfig)) {
+ if (configUpdatedDisplays == null) {
+ configUpdatedDisplays = new ArraySet<>();
+ }
+ configUpdatedDisplays.add(configUpdatedContext.getDisplayId());
+ }
+ }
+
+ item.postExecute(mTransactionHandler, mPendingActions);
+ if (r == null) {
+ // Launch activity request will create an activity record.
+ r = mTransactionHandler.getActivityClient(token);
+ }
+
+ if (postExecutionState != UNDEFINED && r != null) {
+ // Skip the very last transition and perform it by explicit state request instead.
+ final boolean shouldExcludeLastTransition =
+ i == lastCallbackRequestingState && finalState == postExecutionState;
+ cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction);
}
}
- // Can't read flag from isolated process.
- final boolean isSyncWindowConfigUpdateFlagEnabled = !Process.isIsolated()
- && syncWindowConfigUpdateFlag();
- final Context configUpdatedContext = isSyncWindowConfigUpdateFlagEnabled
- ? item.getContextToUpdate(mTransactionHandler)
- : null;
- final Configuration preExecutedConfig = configUpdatedContext != null
- ? new Configuration(configUpdatedContext.getResources().getConfiguration())
- : null;
-
- item.execute(mTransactionHandler, mPendingActions);
-
- if (configUpdatedContext != null) {
- final Configuration postExecutedConfig = configUpdatedContext.getResources()
- .getConfiguration();
- if (!areConfigurationsEqualForDisplay(postExecutedConfig, preExecutedConfig)) {
- mConfigUpdatedDisplayIds.add(configUpdatedContext.getDisplayId());
+ if (configUpdatedDisplays != null) {
+ final ClientTransactionListenerController controller =
+ ClientTransactionListenerController.getInstance();
+ final int displayCount = configUpdatedDisplays.size();
+ for (int i = 0; i < displayCount; i++) {
+ final int displayId = configUpdatedDisplays.valueAt(i);
+ controller.onDisplayChanged(displayId);
}
}
-
- item.postExecute(mTransactionHandler, mPendingActions);
- if (r == null) {
- // Launch activity request will create an activity record.
- r = mTransactionHandler.getActivityClient(token);
- }
-
- if (postExecutionState != UNDEFINED && r != null) {
- cycleToPath(r, postExecutionState, shouldExcludeLastLifecycleState, transaction);
- }
}
- /**
- * Transition to the final state if requested by the transaction.
- * @deprecated use {@link #executeTransactionItems} instead
- */
- @Deprecated
+ /** Transition to the final state if requested by the transaction. */
private void executeLifecycleState(@NonNull ClientTransaction transaction) {
final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
if (lifecycleItem == null) {
@@ -225,11 +189,6 @@
return;
}
- executeLifecycleItem(transaction, lifecycleItem);
- }
-
- private void executeLifecycleItem(@NonNull ClientTransaction transaction,
- @NonNull ActivityLifecycleItem lifecycleItem) {
final IBinder token = lifecycleItem.getActivityToken();
final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
if (DEBUG_RESOLVER) {
diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
index dfbccb4..7e89a5b 100644
--- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java
+++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
@@ -236,39 +236,21 @@
* index 1 will be returned, because ActivityResult request on position 1 will be the last
* request that moves activity to the RESUMED state where it will eventually end.
*/
- static int lastCallbackRequestingState(@NonNull ClientTransaction transaction) {
+ static int lastCallbackRequestingState(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
- if (callbacks == null || callbacks.isEmpty()
- || transaction.getLifecycleStateRequest() == null) {
+ if (callbacks == null || callbacks.size() == 0) {
return -1;
}
- return lastCallbackRequestingStateIndex(callbacks, 0, callbacks.size() - 1,
- transaction.getLifecycleStateRequest().getActivityToken());
- }
- /**
- * Returns the index of the last callback between the start index and last index that requests
- * the state for the given activity token in which that activity will be after execution.
- * If there is a group of callbacks in the end that requests the same specific state or doesn't
- * request any - we will find the first one from such group.
- *
- * E.g. ActivityResult requests RESUMED post-execution state, Configuration does not request any
- * specific state. If there is a sequence
- * Configuration - ActivityResult - Configuration - ActivityResult
- * index 1 will be returned, because ActivityResult request on position 1 will be the last
- * request that moves activity to the RESUMED state where it will eventually end.
- */
- private static int lastCallbackRequestingStateIndex(@NonNull List<ClientTransactionItem> items,
- int startIndex, int lastIndex, @NonNull IBinder activityToken) {
// Go from the back of the list to front, look for the request closes to the beginning that
// requests the state in which activity will end after all callbacks are executed.
int lastRequestedState = UNDEFINED;
int lastRequestingCallback = -1;
- for (int i = lastIndex; i >= startIndex; i--) {
- final ClientTransactionItem item = items.get(i);
- final int postExecutionState = item.getPostExecutionState();
- if (postExecutionState != UNDEFINED && activityToken.equals(item.getActivityToken())) {
- // Found a callback that requests some post-execution state for the given activity.
+ for (int i = callbacks.size() - 1; i >= 0; i--) {
+ final ClientTransactionItem callback = callbacks.get(i);
+ final int postExecutionState = callback.getPostExecutionState();
+ if (postExecutionState != UNDEFINED) {
+ // Found a callback that requests some post-execution state.
if (lastRequestedState == UNDEFINED || lastRequestedState == postExecutionState) {
// It's either a first-from-end callback that requests state or it requests
// the same state as the last one. In both cases, we will use it as the new
@@ -284,53 +266,6 @@
return lastRequestingCallback;
}
- /**
- * For the transaction item at {@code currentIndex}, if it is requesting post execution state,
- * whether or not to exclude the last state. This only returns {@code true} when there is a
- * following explicit {@link ActivityLifecycleItem} requesting the same state for the same
- * activity, so that last state will be covered by the following {@link ActivityLifecycleItem}.
- */
- static boolean shouldExcludeLastLifecycleState(@NonNull List<ClientTransactionItem> items,
- int currentIndex) {
- final ClientTransactionItem item = items.get(currentIndex);
- final IBinder activityToken = item.getActivityToken();
- final int postExecutionState = item.getPostExecutionState();
- if (activityToken == null || postExecutionState == UNDEFINED) {
- // Not a transaction item requesting post execution state.
- return false;
- }
- final int nextLifecycleItemIndex = findNextLifecycleItemIndex(items, currentIndex + 1,
- activityToken);
- if (nextLifecycleItemIndex == -1) {
- // No following ActivityLifecycleItem for this activity token.
- return false;
- }
- final ActivityLifecycleItem lifecycleItem =
- (ActivityLifecycleItem) items.get(nextLifecycleItemIndex);
- if (postExecutionState != lifecycleItem.getTargetState()) {
- // The explicit ActivityLifecycleItem is not requesting the same state.
- return false;
- }
- // Only exclude for the first non-lifecycle item that requests the same specific state.
- return currentIndex == lastCallbackRequestingStateIndex(items, currentIndex,
- nextLifecycleItemIndex - 1, activityToken);
- }
-
- /**
- * Finds the index of the next {@link ActivityLifecycleItem} for the given activity token.
- */
- private static int findNextLifecycleItemIndex(@NonNull List<ClientTransactionItem> items,
- int startIndex, @NonNull IBinder activityToken) {
- final int size = items.size();
- for (int i = startIndex; i < size; i++) {
- final ClientTransactionItem item = items.get(i);
- if (item.isActivityLifecycleItem() && item.getActivityToken().equals(activityToken)) {
- return i;
- }
- }
- return -1;
- }
-
/** Dump transaction to string. */
static String transactionToString(@NonNull ClientTransaction transaction,
@NonNull ClientTransactionHandler transactionHandler) {
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index 8b09bdf..161fa79 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -206,9 +206,8 @@
/**
* @return whether the association is managed by the companion application it belongs to.
* @see AssociationRequest.Builder#setSelfManaged(boolean)
- * @hide
*/
- @SystemApi
+ @SuppressLint("UnflaggedApi") // promoting from @SystemApi
public boolean isSelfManaged() {
return mSelfManaged;
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index bb9cc0b..7b6bad3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4292,6 +4292,14 @@
"com.android.intent.action.SHOW_BRIGHTNESS_DIALOG";
/**
+ * Intent Extra: holds boolean that determines whether brightness dialog is full width when
+ * in landscape mode.
+ * @hide
+ */
+ public static final String EXTRA_BRIGHTNESS_DIALOG_IS_FULL_WIDTH =
+ "android.intent.extra.BRIGHTNESS_DIALOG_IS_FULL_WIDTH";
+
+ /**
* Activity Action: Shows the contrast setting dialog.
* @hide
*/
diff --git a/core/java/android/hardware/HardwareBuffer.aidl b/core/java/android/hardware/HardwareBuffer.aidl
index 1333f0d..a9742cb 100644
--- a/core/java/android/hardware/HardwareBuffer.aidl
+++ b/core/java/android/hardware/HardwareBuffer.aidl
@@ -16,4 +16,4 @@
package android.hardware;
-@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable HardwareBuffer ndk_header "android/hardware_buffer_aidl.h";
+@JavaOnlyStableParcelable @NdkOnlyStableParcelable @RustOnlyStableParcelable parcelable HardwareBuffer ndk_header "android/hardware_buffer_aidl.h" rust_type "nativewindow::HardwareBuffer";
diff --git a/core/java/android/nfc/Constants.java b/core/java/android/nfc/Constants.java
new file mode 100644
index 0000000..f768330
--- /dev/null
+++ b/core/java/android/nfc/Constants.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 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.nfc;
+
+/**
+ * @hide
+ * TODO(b/303286040): Holds @hide API constants. Formalize these APIs.
+ */
+public final class Constants {
+ private Constants() { }
+
+ public static final String SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground";
+ public static final String SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
+ public static final String FEATURE_NFC_ANY = "android.hardware.nfc.any";
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 4658630..4a7bd3f 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -24,6 +24,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.UserIdInt;
import android.app.Activity;
@@ -37,6 +38,7 @@
import android.nfc.tech.Ndef;
import android.nfc.tech.NfcA;
import android.nfc.tech.NfcF;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -1594,6 +1596,40 @@
mNfcActivityManager.disableReaderMode(activity);
}
+ // Flags arguments to NFC adapter to enable/disable NFC
+ private static final int DISABLE_POLLING_FLAGS = 0x1000;
+ private static final int ENABLE_POLLING_FLAGS = 0x0000;
+
+ /**
+ * Privileged API to enable disable reader polling.
+ * Note: Use with caution! The app is responsible for ensuring that the polling state is
+ * returned to normal.
+ *
+ * @see #enableReaderMode(Activity, ReaderCallback, int, Bundle) for more detailed
+ * documentation.
+ *
+ * @param enablePolling whether to enable or disable polling.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @SuppressLint("VisiblySynchronized")
+ public void setReaderMode(boolean enablePolling) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
+ Binder token = new Binder();
+ int flags = enablePolling ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS;
+ try {
+ NfcAdapter.sService.setReaderMode(token, null, flags, null);
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ }
+ }
+
/**
* Manually invoke Android Beam to share data.
*
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 4909b08..32c2a1b 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.nfc.Constants;
import android.nfc.INfcCardEmulation;
import android.nfc.NfcAdapter;
import android.os.RemoteException;
@@ -274,7 +275,7 @@
try {
preferForeground = Settings.Secure.getInt(
contextAsUser.getContentResolver(),
- Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0;
+ Constants.SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND) != 0;
} catch (SettingNotFoundException e) {
}
return preferForeground;
diff --git a/core/java/android/os/OomKillRecord.java b/core/java/android/os/OomKillRecord.java
index 151a65f..ca1d49a 100644
--- a/core/java/android/os/OomKillRecord.java
+++ b/core/java/android/os/OomKillRecord.java
@@ -15,10 +15,15 @@
*/
package android.os;
+import com.android.internal.util.FrameworkStatsLog;
/**
+ * Activity manager communication with kernel out-of-memory (OOM) data handling
+ * and statsd atom logging.
+ *
* Expected data to get back from the OOM event's file.
- * Note that this should be equivalent to the struct <b>OomKill</b> inside
+ * Note that this class fields' should be equivalent to the struct
+ * <b>OomKill</b> inside
* <pre>
* system/memory/libmeminfo/libmemevents/include/memevents.h
* </pre>
@@ -41,6 +46,18 @@
this.mOomScoreAdj = oomScoreAdj;
}
+ /**
+ * Logs the event when the kernel OOM killer claims a victims to reduce
+ * memory pressure.
+ * KernelOomKillOccurred = 754
+ */
+ public void logKillOccurred() {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.KERNEL_OOM_KILL_OCCURRED,
+ mUid, mPid, mOomScoreAdj, mTimeStampInMillis,
+ mProcessName);
+ }
+
public long getTimestampMilli() {
return mTimeStampInMillis;
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 4c8ef97..9034ff1 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3330,7 +3330,10 @@
*
* @return whether the context user is running in the foreground.
*/
- @UserHandleAware
+ @UserHandleAware(
+ requiresAnyOfPermissionsIfNotCaller = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
public boolean isUserForeground() {
try {
return mService.isUserForeground(mUserId);
@@ -3404,11 +3407,10 @@
* @hide
*/
@SystemApi
- @UserHandleAware
- @RequiresPermission(anyOf = {
- "android.permission.INTERACT_ACROSS_USERS",
- "android.permission.MANAGE_USERS"
- })
+ @UserHandleAware(
+ requiresAnyOfPermissionsIfNotCaller = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
public boolean isUserVisible() {
try {
return mService.isUserVisible(mUserId);
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index a391571..27ad45d 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3196,6 +3196,16 @@
public static final String ALWAYS_ON = "always_on";
/**
+ * The infrastructure bitmask which the APN can be used on. For example, some APNs can only
+ * be used when the device is on cellular, on satellite, or both. The default value is
+ * 1 (INFRASTRUCTURE_CELLULAR).
+ *
+ * <P>Type: INTEGER</P>
+ * @hide
+ */
+ public static final String INFRASTRUCTURE_BITMASK = "infrastructure_bitmask";
+
+ /**
* MVNO type:
* {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
* <P>Type: TEXT</P>
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 2f3d73a..42a0c9a 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -70,6 +70,7 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -796,7 +797,7 @@
if (nativeObject != 0) {
// Only add valid surface controls to the registry. This is called at the end of this
// method since its information is dumped if the process threshold is reached.
- addToRegistry();
+ SurfaceControlRegistry.getProcessInstance().add(this);
}
}
@@ -1501,7 +1502,7 @@
if (mCloseGuard != null) {
mCloseGuard.warnIfOpen();
}
- removeFromRegistry();
+ SurfaceControlRegistry.getProcessInstance().remove(this);
} finally {
super.finalize();
}
@@ -1519,6 +1520,10 @@
*/
public void release() {
if (mNativeObject != 0) {
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "release", null, this, null);
+ }
mFreeNativeResources.run();
mNativeObject = 0;
mNativeHandle = 0;
@@ -1532,7 +1537,7 @@
mChoreographer = null;
}
}
- removeFromRegistry();
+ SurfaceControlRegistry.getProcessInstance().remove(this);
}
}
@@ -2765,8 +2770,10 @@
private Transaction(long nativeObject) {
mNativeObject = nativeObject;
- mFreeNativeResources =
- sRegistry.registerNativeAllocation(this, mNativeObject);
+ mFreeNativeResources = sRegistry.registerNativeAllocation(this, mNativeObject);
+ if (!SurfaceControlRegistry.sCallStackDebuggingInitialized) {
+ SurfaceControlRegistry.initializeCallStackDebugging();
+ }
}
private Transaction(Parcel in) {
@@ -2845,6 +2852,11 @@
applyResizedSurfaces();
notifyReparentedSurfaces();
nativeApplyTransaction(mNativeObject, sync, oneWay);
+
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "apply", this, null, null);
+ }
}
/**
@@ -2920,6 +2932,10 @@
@UnsupportedAppUsage
public Transaction show(SurfaceControl sc) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "show", this, sc, null);
+ }
nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
return this;
}
@@ -2934,6 +2950,10 @@
@UnsupportedAppUsage
public Transaction hide(SurfaceControl sc) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "hide", this, sc, null);
+ }
nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
return this;
}
@@ -2950,6 +2970,10 @@
@NonNull
public Transaction setPosition(@NonNull SurfaceControl sc, float x, float y) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setPosition", this, sc, "x=" + x + " y=" + y);
+ }
nativeSetPosition(mNativeObject, sc.mNativeObject, x, y);
return this;
}
@@ -2968,6 +2992,10 @@
checkPreconditions(sc);
Preconditions.checkArgument(scaleX >= 0, "Negative value passed in for scaleX");
Preconditions.checkArgument(scaleY >= 0, "Negative value passed in for scaleY");
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setScale", this, sc, "sx=" + scaleX + " sy=" + scaleY);
+ }
nativeSetScale(mNativeObject, sc.mNativeObject, scaleX, scaleY);
return this;
}
@@ -2985,6 +3013,10 @@
public Transaction setBufferSize(@NonNull SurfaceControl sc,
@IntRange(from = 0) int w, @IntRange(from = 0) int h) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setBufferSize", this, sc, "w=" + w + " h=" + h);
+ }
mResizedSurfaces.put(sc, new Point(w, h));
return this;
}
@@ -3005,6 +3037,10 @@
public Transaction setFixedTransformHint(@NonNull SurfaceControl sc,
@Surface.Rotation int transformHint) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setFixedTransformHint", this, sc, "hint=" + transformHint);
+ }
nativeSetFixedTransformHint(mNativeObject, sc.mNativeObject, transformHint);
return this;
}
@@ -3018,6 +3054,10 @@
@NonNull
public Transaction unsetFixedTransformHint(@NonNull SurfaceControl sc) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "unsetFixedTransformHint", this, sc, null);
+ }
nativeSetFixedTransformHint(mNativeObject, sc.mNativeObject, -1/* INVALID_ROTATION */);
return this;
}
@@ -3035,6 +3075,10 @@
public Transaction setLayer(@NonNull SurfaceControl sc,
@IntRange(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE) int z) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setLayer", this, sc, "z=" + z);
+ }
nativeSetLayer(mNativeObject, sc.mNativeObject, z);
return this;
}
@@ -3044,6 +3088,10 @@
*/
public Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int z) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setRelativeLayer", this, sc, "relTo=" + relativeTo + " z=" + z);
+ }
nativeSetRelativeLayer(mNativeObject, sc.mNativeObject, relativeTo.mNativeObject, z);
return this;
}
@@ -3053,6 +3101,10 @@
*/
public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "unsetFixedTransformHint", this, sc, "region=" + transparentRegion);
+ }
nativeSetTransparentRegionHint(mNativeObject,
sc.mNativeObject, transparentRegion);
return this;
@@ -3069,6 +3121,10 @@
public Transaction setAlpha(@NonNull SurfaceControl sc,
@FloatRange(from = 0.0, to = 1.0) float alpha) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setAlpha", this, sc, "alpha=" + alpha);
+ }
nativeSetAlpha(mNativeObject, sc.mNativeObject, alpha);
return this;
}
@@ -3124,6 +3180,11 @@
public Transaction setMatrix(SurfaceControl sc,
float dsdx, float dtdx, float dtdy, float dsdy) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setMatrix", this, sc,
+ "dsdx=" + dsdx + " dtdx=" + dtdx + " dtdy=" + dtdy + " dsdy=" + dsdy);
+ }
nativeSetMatrix(mNativeObject, sc.mNativeObject,
dsdx, dtdx, dtdy, dsdy);
return this;
@@ -3189,6 +3250,10 @@
@UnsupportedAppUsage
public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setWindowCrop", this, sc, "crop=" + crop);
+ }
if (crop != null) {
nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
@@ -3211,6 +3276,10 @@
*/
public @NonNull Transaction setCrop(@NonNull SurfaceControl sc, @Nullable Rect crop) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setCrop", this, sc, "crop=" + crop);
+ }
if (crop != null) {
Preconditions.checkArgument(crop.isValid(), "Crop isn't valid.");
nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
@@ -3233,6 +3302,10 @@
*/
public Transaction setWindowCrop(SurfaceControl sc, int width, int height) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setCornerRadius", this, sc, "w=" + width + " h=" + height);
+ }
nativeSetWindowCrop(mNativeObject, sc.mNativeObject, 0, 0, width, height);
return this;
}
@@ -3247,6 +3320,10 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Transaction setCornerRadius(SurfaceControl sc, float cornerRadius) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setCornerRadius", this, sc, "cornerRadius=" + cornerRadius);
+ }
nativeSetCornerRadius(mNativeObject, sc.mNativeObject, cornerRadius);
return this;
@@ -3262,6 +3339,10 @@
*/
public Transaction setBackgroundBlurRadius(SurfaceControl sc, int radius) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setBackgroundBlurRadius", this, sc, "radius=" + radius);
+ }
nativeSetBackgroundBlurRadius(mNativeObject, sc.mNativeObject, radius);
return this;
}
@@ -3318,6 +3399,10 @@
public Transaction reparent(@NonNull SurfaceControl sc,
@Nullable SurfaceControl newParent) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "reparent", this, sc, "newParent=" + newParent);
+ }
long otherObject = 0;
if (newParent != null) {
newParent.checkNotReleased();
@@ -3337,6 +3422,11 @@
@UnsupportedAppUsage
public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "reparent", this, sc,
+ "r=" + color[0] + " g=" + color[1] + " b=" + color[2]);
+ }
nativeSetColor(mNativeObject, sc.mNativeObject, color);
return this;
}
@@ -3347,6 +3437,10 @@
*/
public Transaction unsetColor(SurfaceControl sc) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "unsetColor", this, sc, null);
+ }
nativeSetColor(mNativeObject, sc.mNativeObject, INVALID_COLOR);
return this;
}
@@ -3358,6 +3452,10 @@
*/
public Transaction setSecure(SurfaceControl sc, boolean isSecure) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setSecure", this, sc, "secure=" + isSecure);
+ }
if (isSecure) {
nativeSetFlags(mNativeObject, sc.mNativeObject, SECURE, SECURE);
} else {
@@ -3411,6 +3509,10 @@
@NonNull
public Transaction setOpaque(@NonNull SurfaceControl sc, boolean isOpaque) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setOpaque", this, sc, "opaque=" + isOpaque);
+ }
if (isOpaque) {
nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE);
} else {
@@ -3580,6 +3682,10 @@
*/
public Transaction setShadowRadius(SurfaceControl sc, float shadowRadius) {
checkPreconditions(sc);
+ if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
+ SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
+ "setShadowRadius", this, sc, "radius=" + shadowRadius);
+ }
nativeSetShadowRadius(mNativeObject, sc.mNativeObject, shadowRadius);
return this;
}
@@ -4463,26 +4569,6 @@
return -1;
}
- /**
- * Adds this surface control to the registry for this process if it is created.
- */
- private void addToRegistry() {
- final SurfaceControlRegistry registry = SurfaceControlRegistry.getProcessInstance();
- if (registry != null) {
- registry.add(this);
- }
- }
-
- /**
- * Removes this surface control from the registry for this process.
- */
- private void removeFromRegistry() {
- final SurfaceControlRegistry registry = SurfaceControlRegistry.getProcessInstance();
- if (registry != null) {
- registry.remove(this);
- }
- }
-
// Called by native
private static void invokeReleaseCallback(Consumer<SyncFence> callback, long nativeFencePtr) {
SyncFence fence = new SyncFence(nativeFencePtr);
diff --git a/core/java/android/view/SurfaceControlRegistry.java b/core/java/android/view/SurfaceControlRegistry.java
index 0f35048..52be8f6 100644
--- a/core/java/android/view/SurfaceControlRegistry.java
+++ b/core/java/android/view/SurfaceControlRegistry.java
@@ -23,7 +23,9 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.content.Context;
+import android.os.Build;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -104,6 +106,9 @@
// Number of surface controls to dump when the max threshold is exceeded
private static final int DUMP_LIMIT = 256;
+ // An instance of a registry that is a no-op
+ private static final SurfaceControlRegistry NO_OP_REGISTRY = new NoOpRegistry();
+
// Static lock, must be held for all registry operations
private static final Object sLock = new Object();
@@ -113,6 +118,22 @@
// The registry for a given process
private static volatile SurfaceControlRegistry sProcessRegistry;
+ // Whether call stack debugging has been initialized. This is evaluated only once per process
+ // instance when the first SurfaceControl.Transaction object is created
+ static boolean sCallStackDebuggingInitialized;
+
+ // Whether call stack debugging is currently enabled, ie. whether there is a valid match string
+ // for either a specific surface control name or surface control transaction method
+ static boolean sCallStackDebuggingEnabled;
+
+ // The name of the surface control to log stack traces for. Always non-null if
+ // sCallStackDebuggingEnabled is true. Can be combined with the match call.
+ private static String sCallStackDebuggingMatchName;
+
+ // The surface control transaction method name to log stack traces for. Always non-null if
+ // sCallStackDebuggingEnabled is true. Can be combined with the match name.
+ private static String sCallStackDebuggingMatchCall;
+
// Mapping of the active SurfaceControls to the elapsed time when they were registered
@GuardedBy("sLock")
private final WeakHashMap<SurfaceControl, Long> mSurfaceControls;
@@ -160,6 +181,12 @@
}
}
+ @VisibleForTesting
+ public void setCallStackDebuggingParams(String matchName, String matchCall) {
+ sCallStackDebuggingMatchName = matchName.toLowerCase();
+ sCallStackDebuggingMatchCall = matchCall.toLowerCase();
+ }
+
/**
* Creates and initializes the registry for all SurfaceControls in this process. The caller must
* hold the READ_FRAME_BUFFER permission.
@@ -196,11 +223,9 @@
* createProcessInstance(Context) was previously called from a valid caller.
* @hide
*/
- @Nullable
- @VisibleForTesting
public static SurfaceControlRegistry getProcessInstance() {
synchronized (sLock) {
- return sProcessRegistry;
+ return sProcessRegistry != null ? sProcessRegistry : NO_OP_REGISTRY;
}
}
@@ -248,6 +273,91 @@
}
/**
+ * Initializes global call stack debugging if this is a debug build and a filter is specified.
+ * This is a no-op if
+ *
+ * Usage:
+ * adb shell setprop persist.wm.debug.sc.tx.log_match_call <call or \"\" to unset>
+ * adb shell setprop persist.wm.debug.sc.tx.log_match_name <name or \"\" to unset>
+ * adb reboot
+ */
+ final static void initializeCallStackDebugging() {
+ if (sCallStackDebuggingInitialized || !Build.IS_DEBUGGABLE) {
+ // Return early if already initialized or this is not a debug build
+ return;
+ }
+
+ sCallStackDebuggingInitialized = true;
+ sCallStackDebuggingMatchCall =
+ SystemProperties.get("persist.wm.debug.sc.tx.log_match_call", null)
+ .toLowerCase();
+ sCallStackDebuggingMatchName =
+ SystemProperties.get("persist.wm.debug.sc.tx.log_match_name", null)
+ .toLowerCase();
+ // Only enable stack debugging if any of the match filters are set
+ sCallStackDebuggingEnabled = (!sCallStackDebuggingMatchCall.isEmpty()
+ || !sCallStackDebuggingMatchName.isEmpty());
+ if (sCallStackDebuggingEnabled) {
+ Log.d(TAG, "Enabling transaction call stack debugging:"
+ + " matchCall=" + sCallStackDebuggingMatchCall
+ + " matchName=" + sCallStackDebuggingMatchName);
+ }
+ }
+
+ /**
+ * Dumps the callstack if it matches the global debug properties. Caller should first verify
+ * {@link #sCallStackDebuggingEnabled} is true.
+ *
+ * @param call the name of the call
+ * @param tx (optional) the transaction associated with this call
+ * @param sc the affected surface
+ * @param details additional details to print with the stack track
+ */
+ final void checkCallStackDebugging(@NonNull String call,
+ @Nullable SurfaceControl.Transaction tx, @Nullable SurfaceControl sc,
+ @Nullable String details) {
+ if (!sCallStackDebuggingEnabled) {
+ return;
+ }
+ if (!matchesForCallStackDebugging(sc != null ? sc.getName() : null, call)) {
+ return;
+ }
+ final String txMsg = tx != null ? "tx=" + tx.getId() + " ": "";
+ final String scMsg = sc != null ? " sc=" + sc.getName() + "": "";
+ final String msg = details != null
+ ? call + " (" + txMsg + scMsg + ") " + details
+ : call + " (" + txMsg + scMsg + ")";
+ Log.e(TAG, msg, new Throwable());
+ }
+
+ /**
+ * Tests whether the given surface control name/method call matches the filters set for the
+ * call stack debugging.
+ */
+ @VisibleForTesting
+ public final boolean matchesForCallStackDebugging(@Nullable String name, @NonNull String call) {
+ final boolean matchCall = !sCallStackDebuggingMatchCall.isEmpty();
+ if (matchCall && !call.toLowerCase().contains(sCallStackDebuggingMatchCall)) {
+ // Skip if target call doesn't match requested caller
+ return false;
+ }
+ final boolean matchName = !sCallStackDebuggingMatchName.isEmpty();
+ if (matchName && (name == null
+ || !name.toLowerCase().contains(sCallStackDebuggingMatchName))) {
+ // Skip if target surface doesn't match requested surface
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns whether call stack debugging is enabled for this process.
+ */
+ final static boolean isCallStackDebuggingEnabled() {
+ return sCallStackDebuggingEnabled;
+ }
+
+ /**
* Forces the gc and finalizers to run, used prior to dumping to ensure we only dump strongly
* referenced surface controls.
*/
@@ -272,7 +382,27 @@
synchronized (sLock) {
if (sProcessRegistry != null) {
sDefaultReporter.onMaxLayersExceeded(sProcessRegistry.mSurfaceControls, limit, pw);
+ pw.println("sCallStackDebuggingInitialized=" + sCallStackDebuggingInitialized);
+ pw.println("sCallStackDebuggingEnabled=" + sCallStackDebuggingEnabled);
+ pw.println("sCallStackDebuggingMatchName=" + sCallStackDebuggingMatchName);
+ pw.println("sCallStackDebuggingMatchCall=" + sCallStackDebuggingMatchCall);
}
}
}
+
+ /**
+ * A no-op implementation of the registry.
+ */
+ private static class NoOpRegistry extends SurfaceControlRegistry {
+
+ @Override
+ public void setReportingThresholds(int maxLayersReportingThreshold,
+ int resetReportingThreshold, Reporter reporter) {}
+
+ @Override
+ void add(SurfaceControl sc) {}
+
+ @Override
+ void remove(SurfaceControl sc) {}
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 49b16c7..e9d0e4c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -19,8 +19,6 @@
import static android.content.res.Resources.ID_NULL;
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
-import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
-import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
@@ -29,7 +27,6 @@
import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH;
import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE;
import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
-import static android.view.flags.Flags.toolkitSetFrameRate;
import static android.view.flags.Flags.viewVelocityApi;
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS;
@@ -117,7 +114,6 @@
import android.text.InputType;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.DisplayMetrics;
import android.util.FloatProperty;
import android.util.LayoutDirection;
import android.util.Log;
@@ -5513,11 +5509,6 @@
private ViewTranslationResponse mViewTranslationResponse;
/**
- * A threshold value to determine the frame rate category of the View based on the size.
- */
- private static final float FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD = 0.07f;
-
- /**
* Simple constructor to use when creating a view from code.
*
* @param context The Context the view is running in, through which it can
@@ -20192,9 +20183,6 @@
return;
}
- // For VRR to vote the preferred frame rate
- votePreferredFrameRate();
-
// Reset content capture caches
mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK;
mContentCaptureSessionCached = false;
@@ -20297,8 +20285,6 @@
*/
protected void damageInParent() {
if (mParent != null && mAttachInfo != null) {
- // For VRR to vote the preferred frame rate
- votePreferredFrameRate();
mParent.onDescendantInvalidated(this, this);
}
}
@@ -32995,40 +32981,6 @@
return null;
}
- private float getSizePercentage() {
- if (mResources == null || getAlpha() == 0 || getVisibility() != VISIBLE) {
- return 0;
- }
-
- DisplayMetrics displayMetrics = mResources.getDisplayMetrics();
- int screenSize = displayMetrics.widthPixels
- * displayMetrics.heightPixels;
- int viewSize = getWidth() * getHeight();
-
- if (screenSize == 0 || viewSize == 0) {
- return 0f;
- }
- return (float) viewSize / screenSize;
- }
-
- private int calculateFrameRateCategory() {
- float sizePercentage = getSizePercentage();
-
- if (sizePercentage <= FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD) {
- return FRAME_RATE_CATEGORY_LOW;
- } else {
- return FRAME_RATE_CATEGORY_NORMAL;
- }
- }
-
- private void votePreferredFrameRate() {
- // use toolkitSetFrameRate flag to gate the change
- ViewRootImpl viewRootImpl = getViewRootImpl();
- if (toolkitSetFrameRate() && viewRootImpl != null && getSizePercentage() > 0) {
- viewRootImpl.votePreferredFrameRateCategory(calculateFrameRateCategory());
- }
- }
-
/**
* Set the current velocity of the View, we only track positive value.
* We will use the velocity information to adjust the frame rate when applicable.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 50eeed8..4a10cab 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -24,8 +24,6 @@
import static android.view.Display.INVALID_DISPLAY;
import static android.view.InputDevice.SOURCE_CLASS_NONE;
import static android.view.InsetsSource.ID_IME;
-import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
-import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
import static android.view.View.PFLAG_DRAW_ANIMATION;
import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
@@ -76,10 +74,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
@@ -92,7 +87,6 @@
import static android.view.accessibility.Flags.forceInvertColor;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
-import static android.view.flags.Flags.toolkitSetFrameRate;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
@@ -661,6 +655,10 @@
*/
private boolean mCheckIfCanDraw = false;
+ private boolean mWasLastDrawCanceled;
+ private boolean mLastTraversalWasVisible = true;
+ private boolean mLastDrawScreenOff;
+
private boolean mDrewOnceForSync = false;
int mSyncSeqId = 0;
@@ -738,7 +736,6 @@
private SurfaceControl mBoundsLayer;
private final SurfaceSession mSurfaceSession = new SurfaceSession();
private final Transaction mTransaction = new Transaction();
- private final Transaction mFrameRateTransaction = new Transaction();
@UnsupportedAppUsage
boolean mAdded;
@@ -962,34 +959,6 @@
private AccessibilityWindowAttributes mAccessibilityWindowAttributes;
- /*
- * for Variable Refresh Rate project
- */
-
- // The preferred frame rate category of the view that
- // could be updated on a frame-by-frame basis.
- private int mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
- // The preferred frame rate category of the last frame that
- // could be used to lower frame rate after touch boost
- private int mLastPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
- // The preferred frame rate of the view that is mainly used for
- // touch boosting, view velocity handling, and TextureView.
- private float mPreferredFrameRate = 0;
- // Used to check if there were any view invalidations in
- // the previous time frame (FRAME_RATE_IDLENESS_REEVALUATE_TIME).
- private boolean mHasInvalidation = false;
- // Used to check if it is in the touch boosting period.
- private boolean mIsFrameRateBoosting = false;
- // Used to check if there is a message in the message queue
- // for idleness handling.
- private boolean mHasIdledMessage = false;
- // time for touch boost period.
- private static final int FRAME_RATE_TOUCH_BOOST_TIME = 1500;
- // time for checking idle status periodically.
- private static final int FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS = 500;
- // time for revaluating the idle status before lowering the frame rate.
- private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 500;
-
/**
* A temporary object used so relayoutWindow can return the latest SyncSeqId
* system. The SyncSeqId system was designed to work without synchronous relayout
@@ -1926,12 +1895,19 @@
}
void handleAppVisibility(boolean visible) {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.instant(Trace.TRACE_TAG_VIEW, TextUtils.formatSimple(
+ "%s visibilityChanged oldVisibility=%b newVisibility=%b", mTag,
+ mAppVisible, visible));
+ }
if (mAppVisible != visible) {
final boolean previousVisible = getHostVisibility() == View.VISIBLE;
mAppVisible = visible;
final boolean currentVisible = getHostVisibility() == View.VISIBLE;
// Root view only cares about whether it is visible or not.
if (previousVisible != currentVisible) {
+ Log.d(mTag, "visibilityChanged oldVisibility=" + previousVisible + " newVisibility="
+ + currentVisible);
mAppVisibilityChanged = true;
scheduleTraversals();
}
@@ -3292,8 +3268,8 @@
|| mForceNextWindowRelayout) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
- TextUtils.formatSimple("relayoutWindow#"
- + "first=%b/resize=%b/vis=%b/params=%b/force=%b",
+ TextUtils.formatSimple("%s-relayoutWindow#"
+ + "first=%b/resize=%b/vis=%b/params=%b/force=%b", mTag,
mFirst, windowShouldResize, viewVisibilityChanged, params != null,
mForceNextWindowRelayout));
}
@@ -3882,11 +3858,7 @@
boolean cancelDueToPreDrawListener = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
boolean cancelAndRedraw = cancelDueToPreDrawListener
|| (cancelDraw && mDrewOnceForSync);
- if (cancelAndRedraw) {
- Log.d(mTag, "Cancelling draw."
- + " cancelDueToPreDrawListener=" + cancelDueToPreDrawListener
- + " cancelDueToSync=" + (cancelDraw && mDrewOnceForSync));
- }
+
if (!cancelAndRedraw) {
// A sync was already requested before the WMS requested sync. This means we need to
// sync the buffer, regardless if WMS wants to sync the buffer.
@@ -3910,6 +3882,9 @@
}
if (!isViewVisible) {
+ if (mLastTraversalWasVisible) {
+ logAndTrace("Not drawing due to not visible");
+ }
mLastPerformTraversalsSkipDrawReason = "view_not_visible";
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
@@ -3921,12 +3896,23 @@
handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
mPendingTransaction, "view not visible");
} else if (cancelAndRedraw) {
+ if (!mWasLastDrawCanceled) {
+ logAndTrace("Canceling draw."
+ + " cancelDueToPreDrawListener=" + cancelDueToPreDrawListener
+ + " cancelDueToSync=" + (cancelDraw && mDrewOnceForSync));
+ }
mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason()
: "cancel_" + cancelReason;
// Try again
scheduleTraversals();
} else {
+ if (mWasLastDrawCanceled) {
+ logAndTrace("Draw frame after cancel");
+ }
+ if (!mLastTraversalWasVisible) {
+ logAndTrace("Start draw after previous draw not visible");
+ }
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
@@ -3938,6 +3924,8 @@
mPendingTransaction, mLastPerformDrawSkippedReason);
}
}
+ mWasLastDrawCanceled = cancelAndRedraw;
+ mLastTraversalWasVisible = isViewVisible;
if (mAttachInfo.mContentCaptureEvents != null) {
notifyContentCaptureEvents();
@@ -3958,12 +3946,6 @@
mWmsRequestSyncGroupState = WMS_SYNC_NONE;
}
}
-
- // For the variable refresh rate project.
- setPreferredFrameRate(mPreferredFrameRate);
- setPreferredFrameRateCategory(mPreferredFrameRateCategory);
- mLastPreferredFrameRateCategory = mPreferredFrameRateCategory;
- mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
}
private void createSyncIfNeeded() {
@@ -4733,10 +4715,7 @@
return didProduceBuffer -> {
if (!didProduceBuffer) {
- Trace.instant(Trace.TRACE_TAG_VIEW,
- "Transaction not synced due to no frame drawn-" + mTag);
- Log.d(mTag, "Pending transaction will not be applied in sync with a draw "
- + "because there was nothing new to draw");
+ logAndTrace("Transaction not synced due to no frame drawn");
mBlastBufferQueue.applyPendingTransactions(frame);
}
};
@@ -4753,17 +4732,26 @@
mLastPerformDrawSkippedReason = null;
if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
mLastPerformDrawSkippedReason = "screen_off";
+ if (!mLastDrawScreenOff) {
+ logAndTrace("Not drawing due to screen off");
+ }
+ mLastDrawScreenOff = true;
return false;
} else if (mView == null) {
mLastPerformDrawSkippedReason = "no_root_view";
return false;
}
+ if (mLastDrawScreenOff) {
+ logAndTrace("Resumed drawing after screen turned on");
+ mLastDrawScreenOff = false;
+ }
+
final boolean fullRedrawNeeded = mFullRedrawNeeded || surfaceSyncGroup != null;
mFullRedrawNeeded = false;
mIsDrawing = true;
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, mTag + "-draw");
addFrameCommitCallbackIfNeeded();
@@ -6016,8 +6004,6 @@
private static final int MSG_REPORT_KEEP_CLEAR_RECTS = 36;
private static final int MSG_PAUSED_FOR_SYNC_TIMEOUT = 37;
private static final int MSG_DECOR_VIEW_GESTURE_INTERCEPTION = 38;
- private static final int MSG_TOUCH_BOOST_TIMEOUT = 39;
- private static final int MSG_CHECK_INVALIDATION_IDLE = 40;
final class ViewRootHandler extends Handler {
@Override
@@ -6313,32 +6299,6 @@
mNumPausedForSync = 0;
scheduleTraversals();
break;
- case MSG_TOUCH_BOOST_TIMEOUT:
- /**
- * Lower the frame rate after the boosting period (FRAME_RATE_TOUCH_BOOST_TIME).
- */
- mIsFrameRateBoosting = false;
- setPreferredFrameRateCategory(Math.max(mPreferredFrameRateCategory,
- mLastPreferredFrameRateCategory));
- break;
- case MSG_CHECK_INVALIDATION_IDLE:
- if (!mHasInvalidation && !mIsFrameRateBoosting) {
- mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
- setPreferredFrameRateCategory(mPreferredFrameRateCategory);
- mHasIdledMessage = false;
- } else {
- /**
- * If there is no invalidation within a certain period,
- * we consider the display is idled.
- * We then set the frame rate catetogry to NO_PREFERENCE.
- * Note that SurfaceFlinger also has a mechanism to lower the refresh rate
- * if there is no updates of the buffer.
- */
- mHasInvalidation = false;
- mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
- FRAME_RATE_IDLENESS_REEVALUATE_TIME);
- }
- break;
}
}
}
@@ -7281,7 +7241,6 @@
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
- final int action = event.getAction();
boolean handled = mHandwritingInitiator.onTouchEvent(event);
if (handled) {
// If handwriting is started, toolkit doesn't receive ACTION_UP.
@@ -7302,22 +7261,6 @@
scheduleConsumeBatchedInputImmediately();
}
}
-
- // For the variable refresh rate project
- if (handled && shouldTouchBoost(action, mWindowAttributes.type)) {
- // set the frame rate to the maximum value.
- mIsFrameRateBoosting = true;
- setPreferredFrameRateCategory(mPreferredFrameRateCategory);
- }
- /**
- * We want to lower the refresh rate when MotionEvent.ACTION_UP,
- * MotionEvent.ACTION_CANCEL is detected.
- * Not using ACTION_MOVE to avoid checking and sending messages too frequently.
- */
- if (mIsFrameRateBoosting && (action == MotionEvent.ACTION_UP
- || action == MotionEvent.ACTION_CANCEL)) {
- sendDelayedEmptyMessage(MSG_TOUCH_BOOST_TIMEOUT, FRAME_RATE_TOUCH_BOOST_TIME);
- }
return handled ? FINISH_HANDLED : FORWARD;
}
@@ -11517,8 +11460,7 @@
@Override
public boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t) {
if (mRemoved || !isHardwareEnabled()) {
- Trace.instant(Trace.TRACE_TAG_VIEW, "applyTransactionOnDraw applyImmediately-" + mTag);
- Log.d(mTag, "applyTransactionOnDraw: Applying transaction immediately");
+ logAndTrace("applyTransactionOnDraw applyImmediately");
t.apply();
} else {
Trace.instant(Trace.TRACE_TAG_VIEW, "applyTransactionOnDraw-" + mTag);
@@ -11906,93 +11848,10 @@
t.clearTrustedPresentationCallback(getSurfaceControl());
}
- private void setPreferredFrameRateCategory(int preferredFrameRateCategory) {
- if (!shouldSetFrameRateCategory()) {
- return;
+ private void logAndTrace(String msg) {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.instant(Trace.TRACE_TAG_VIEW, mTag + "-" + msg);
}
-
- int frameRateCategory = mIsFrameRateBoosting
- ? FRAME_RATE_CATEGORY_HIGH : preferredFrameRateCategory;
-
- try {
- mFrameRateTransaction.setFrameRateCategory(mSurfaceControl,
- frameRateCategory, false).apply();
- } catch (Exception e) {
- Log.e(mTag, "Unable to set frame rate category", e);
- }
-
- if (mPreferredFrameRateCategory != FRAME_RATE_CATEGORY_NO_PREFERENCE && !mHasIdledMessage) {
- // Check where the display is idled periodically.
- // If so, set the frame rate category to NO_PREFERENCE
- mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
- FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS);
- mHasIdledMessage = true;
- }
- }
-
- private void setPreferredFrameRate(float preferredFrameRate) {
- if (!shouldSetFrameRate()) {
- return;
- }
-
- try {
- mFrameRateTransaction.setFrameRate(mSurfaceControl,
- preferredFrameRate, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT).apply();
- } catch (Exception e) {
- Log.e(mTag, "Unable to set frame rate", e);
- }
- }
-
- private void sendDelayedEmptyMessage(int message, int delayedTime) {
- mHandler.removeMessages(message);
-
- mHandler.sendEmptyMessageDelayed(message, delayedTime);
- }
-
- private boolean shouldSetFrameRateCategory() {
- // use toolkitSetFrameRate flag to gate the change
- return mSurface.isValid() && toolkitSetFrameRate();
- }
-
- private boolean shouldSetFrameRate() {
- // use toolkitSetFrameRate flag to gate the change
- return mPreferredFrameRate > 0 && toolkitSetFrameRate();
- }
-
- private boolean shouldTouchBoost(int motionEventAction, int windowType) {
- boolean desiredAction = motionEventAction == MotionEvent.ACTION_DOWN
- || motionEventAction == MotionEvent.ACTION_MOVE
- || motionEventAction == MotionEvent.ACTION_UP;
- boolean desiredType = windowType == TYPE_BASE_APPLICATION || windowType == TYPE_APPLICATION
- || windowType == TYPE_APPLICATION_STARTING || windowType == TYPE_DRAWN_APPLICATION;
- // use toolkitSetFrameRate flag to gate the change
- return desiredAction && desiredType && toolkitSetFrameRate();
- }
-
- /**
- * Allow Views to vote for the preferred frame rate category
- *
- * @param frameRateCategory the preferred frame rate category of a View
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
- public void votePreferredFrameRateCategory(int frameRateCategory) {
- mPreferredFrameRateCategory = Math.max(mPreferredFrameRateCategory, frameRateCategory);
- mHasInvalidation = true;
- }
-
- /**
- * Get the value of mPreferredFrameRateCategory
- */
- @VisibleForTesting
- public int getPreferredFrameRateCategory() {
- return mPreferredFrameRateCategory;
- }
-
- /**
- * Get the value of mPreferredFrameRate
- */
- @VisibleForTesting
- public float getPreferredFrameRate() {
- return mPreferredFrameRate;
+ Log.d(mTag, msg);
}
}
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index cc612ed..6888b50 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -1,10 +1,12 @@
package: "android.view.accessibility"
+# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
+
flag {
+ name: "a11y_overlay_callbacks"
namespace: "accessibility"
- name: "force_invert_color"
- description: "Enable force force-dark for smart inversion and dark theme everywhere"
- bug: "282821643"
+ description: "Whether to allow the passing of result callbacks when attaching a11y overlays."
+ bug: "304478691"
}
flag {
@@ -15,8 +17,8 @@
}
flag {
- name: "a11y_overlay_callbacks"
namespace: "accessibility"
- description: "Whether to allow the passing of result callbacks when attaching a11y overlays."
- bug: "304478691"
+ name: "force_invert_color"
+ description: "Enable force force-dark for smart inversion and dark theme everywhere"
+ bug: "282821643"
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 17c82b6..a0628c4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9854,7 +9854,10 @@
outAttrs.initialCapsMode = ic.getCursorCapsMode(getInputType());
outAttrs.setInitialSurroundingText(mText);
outAttrs.contentMimeTypes = getReceiveContentMimeTypes();
-
+ if (android.view.inputmethod.Flags.editorinfoHandwritingEnabled()
+ && isAutoHandwritingEnabled()) {
+ outAttrs.setStylusHandwritingEnabled(true);
+ }
ArrayList<Class<? extends HandwritingGesture>> gestures = new ArrayList<>();
gestures.add(SelectGesture.class);
gestures.add(SelectRangeGesture.class);
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 7cfd35b..79b3b4f 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -8,6 +8,14 @@
}
flag {
+ name: "defer_display_updates"
+ namespace: "window_manager"
+ description: "Feature flag for deferring DisplayManager updates to WindowManager if Shell transition is running"
+ bug: "259220649"
+ is_fixed_read_only: true
+}
+
+flag {
name: "close_to_square_config_includes_status_bar"
namespace: "windowing_frontend"
description: "On close to square display, when necessary, configuration includes status bar"
diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
index b1d22e0..77e1502 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
@@ -81,11 +81,6 @@
public static final Flag PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS = releasedFlag(
"persist.sysui.notification.propagate_channel_updates_to_conversations");
- // TODO: b/291907312 - remove feature flags
- /** Gating the NMS->NotificationAttentionHelper buzzBeepBlink refactor */
- public static final Flag ENABLE_ATTENTION_HELPER_REFACTOR = devFlag(
- "persist.debug.sysui.notification.enable_attention_helper_refactor");
-
// TODO b/291899544: for released flags, use resource config values
/** Value used by polite notif. feature */
public static final Flag NOTIF_COOLDOWN_T1 = devFlag(
diff --git a/core/proto/android/nfc/Android.bp b/core/proto/android/nfc/Android.bp
deleted file mode 100644
index 6a62c91..0000000
--- a/core/proto/android/nfc/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Copyright (C) 2023 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 {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-filegroup {
- name: "srcs_nfc_proto",
- srcs: [
- "*.proto",
- ],
-}
-
-// Will be statically linked by `framework-nfc`.
-java_library {
- name: "nfc-proto-java-gen",
- installable: false,
- proto: {
- type: "stream",
- include_dirs: [
- "external/protobuf/src",
- ],
- },
- srcs: [
- ":srcs_nfc_proto",
- ],
- sdk_version: "current",
- min_sdk_version: "current",
-}
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 445ddf5..2993a0e 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -65,7 +65,6 @@
"device-time-shell-utils",
"testables",
"com.android.text.flags-aconfig-java",
- "flag-junit",
],
libs: [
@@ -76,7 +75,6 @@
"framework",
"ext",
"framework-res",
- "android.view.flags-aconfig-java",
],
jni_libs: [
"libpowermanagertest_jni",
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
index d10cf16..531404b 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
@@ -62,24 +62,4 @@
verify(callback2, times(1)).preExecute(clientTransactionHandler);
verify(stateRequest, times(1)).preExecute(clientTransactionHandler);
}
-
- @Test
- public void testPreExecuteTransactionItems() {
- final ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
- final ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
- final ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
- final ClientTransactionHandler clientTransactionHandler =
- mock(ClientTransactionHandler.class);
-
- final ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
- transaction.addTransactionItem(callback1);
- transaction.addTransactionItem(callback2);
- transaction.addTransactionItem(stateRequest);
-
- transaction.preExecute(clientTransactionHandler);
-
- verify(callback1, times(1)).preExecute(clientTransactionHandler);
- verify(callback2, times(1)).preExecute(clientTransactionHandler);
- verify(stateRequest, times(1)).preExecute(clientTransactionHandler);
- }
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index f2b0f2e..44a4d58 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -247,31 +247,6 @@
}
@Test
- public void testExecuteTransactionItems_transactionResolution() {
- ClientTransactionItem callback1 = mock(ClientTransactionItem.class);
- when(callback1.getPostExecutionState()).thenReturn(UNDEFINED);
- ClientTransactionItem callback2 = mock(ClientTransactionItem.class);
- when(callback2.getPostExecutionState()).thenReturn(UNDEFINED);
- ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
- IBinder token = mock(IBinder.class);
- when(stateRequest.getActivityToken()).thenReturn(token);
- when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class));
-
- ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
- transaction.addTransactionItem(callback1);
- transaction.addTransactionItem(callback2);
- transaction.addTransactionItem(stateRequest);
-
- transaction.preExecute(mTransactionHandler);
- mExecutor.execute(transaction);
-
- InOrder inOrder = inOrder(mTransactionHandler, callback1, callback2, stateRequest);
- inOrder.verify(callback1).execute(eq(mTransactionHandler), any());
- inOrder.verify(callback2).execute(eq(mTransactionHandler), any());
- inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any());
- }
-
- @Test
public void testDoNotLaunchDestroyedActivity() {
final Map<IBinder, DestroyActivityItem> activitiesToBeDestroyed = new ArrayMap<>();
when(mTransactionHandler.getActivitiesToBeDestroyed()).thenReturn(activitiesToBeDestroyed);
@@ -304,43 +279,12 @@
}
@Test
- public void testExecuteTransactionItems_doNotLaunchDestroyedActivity() {
- final Map<IBinder, DestroyActivityItem> activitiesToBeDestroyed = new ArrayMap<>();
- when(mTransactionHandler.getActivitiesToBeDestroyed()).thenReturn(activitiesToBeDestroyed);
- // Assume launch transaction is still in queue, so there is no client record.
- when(mTransactionHandler.getActivityClient(any())).thenReturn(null);
-
- // An incoming destroy transaction enters binder thread (preExecute).
- final IBinder token = mock(IBinder.class);
- final ClientTransaction destroyTransaction = ClientTransaction.obtain(null /* client */);
- destroyTransaction.addTransactionItem(
- DestroyActivityItem.obtain(token, false /* finished */, 0 /* configChanges */));
- destroyTransaction.preExecute(mTransactionHandler);
- // The activity should be added to to-be-destroyed container.
- assertEquals(1, activitiesToBeDestroyed.size());
-
- // A previous queued launch transaction runs on main thread (execute).
- final ClientTransaction launchTransaction = ClientTransaction.obtain(null /* client */);
- final LaunchActivityItem launchItem =
- spy(new LaunchActivityItemBuilder().setActivityToken(token).build());
- launchTransaction.addTransactionItem(launchItem);
- mExecutor.execute(launchTransaction);
-
- // The launch transaction should not be executed because its token is in the
- // to-be-destroyed container.
- verify(launchItem, never()).execute(any(), any());
-
- // After the destroy transaction has been executed, the token should be removed.
- mExecutor.execute(destroyTransaction);
- assertTrue(activitiesToBeDestroyed.isEmpty());
- }
-
- @Test
public void testActivityResultRequiredStateResolution() {
when(mTransactionHandler.getActivity(any())).thenReturn(mock(Activity.class));
PostExecItem postExecItem = new PostExecItem(ON_RESUME);
+ IBinder token = mock(IBinder.class);
ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
transaction.addCallback(postExecItem);
@@ -356,26 +300,6 @@
}
@Test
- public void testExecuteTransactionItems_activityResultRequiredStateResolution() {
- when(mTransactionHandler.getActivity(any())).thenReturn(mock(Activity.class));
-
- PostExecItem postExecItem = new PostExecItem(ON_RESUME);
-
- ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
- transaction.addTransactionItem(postExecItem);
-
- // Verify resolution that should get to onPause
- mClientRecord.setState(ON_RESUME);
- mExecutor.executeTransactionItems(transaction);
- verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_PAUSE), eq(transaction));
-
- // Verify resolution that should get to onStart
- mClientRecord.setState(ON_STOP);
- mExecutor.executeTransactionItems(transaction);
- verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_START), eq(transaction));
- }
-
- @Test
public void testClosestStateResolutionForSameState() {
final int[] allStates = new int[] {
ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY};
@@ -520,18 +444,6 @@
mExecutor.executeCallbacks(transaction);
}
- @Test(expected = IllegalArgumentException.class)
- public void testExecuteTransactionItems_activityItemNullRecordThrowsException() {
- final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class);
- when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED);
- final IBinder token = mock(IBinder.class);
- final ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
- transaction.addTransactionItem(activityItem);
- when(mTransactionHandler.getActivityClient(token)).thenReturn(null);
-
- mExecutor.executeTransactionItems(transaction);
- }
-
@Test
public void testActivityItemExecute() {
final IBinder token = mock(IBinder.class);
@@ -552,26 +464,6 @@
inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any());
}
- @Test
- public void testExecuteTransactionItems_activityItemExecute() {
- final IBinder token = mock(IBinder.class);
- final ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
- final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class);
- when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED);
- when(activityItem.getActivityToken()).thenReturn(token);
- transaction.addTransactionItem(activityItem);
- final ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
- transaction.addTransactionItem(stateRequest);
- when(stateRequest.getActivityToken()).thenReturn(token);
- when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class));
-
- mExecutor.execute(transaction);
-
- final InOrder inOrder = inOrder(activityItem, stateRequest);
- inOrder.verify(activityItem).execute(eq(mTransactionHandler), eq(mClientRecord), any());
- inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any());
- }
-
private static int[] shuffledArray(int[] inputArray) {
final List<Integer> list = Arrays.stream(inputArray).boxed().collect(Collectors.toList());
Collections.shuffle(list);
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 4aa62c5..7d047c9 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -285,10 +285,6 @@
78 /* configChanges */);
ClientTransaction transaction = ClientTransaction.obtain(null /* client */);
- transaction.addTransactionItem(callback1);
- transaction.addTransactionItem(callback2);
- transaction.addTransactionItem(lifecycleRequest);
-
transaction.addCallback(callback1);
transaction.addCallback(callback2);
transaction.setLifecycleStateRequest(lifecycleRequest);
diff --git a/core/tests/coretests/src/android/view/SurfaceControlRegistryTests.java b/core/tests/coretests/src/android/view/SurfaceControlRegistryTests.java
index e117051..71bdce4 100644
--- a/core/tests/coretests/src/android/view/SurfaceControlRegistryTests.java
+++ b/core/tests/coretests/src/android/view/SurfaceControlRegistryTests.java
@@ -23,6 +23,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.eq;
@@ -148,6 +149,28 @@
reporter.assertLastReportedSetEquals(sc5, sc6, sc7, sc8);
}
+ @Test
+ public void testCallStackDebugging_matchesFilters() {
+ SurfaceControlRegistry registry = SurfaceControlRegistry.getProcessInstance();
+
+ // Specific name, any call
+ registry.setCallStackDebuggingParams("com.android.app1", "");
+ assertFalse(registry.matchesForCallStackDebugging("com.android.noMatchApp", "setAlpha"));
+ assertTrue(registry.matchesForCallStackDebugging("com.android.app1", "setAlpha"));
+
+ // Any name, specific call
+ registry.setCallStackDebuggingParams("", "setAlpha");
+ assertFalse(registry.matchesForCallStackDebugging("com.android.app1", "setLayer"));
+ assertTrue(registry.matchesForCallStackDebugging("com.android.app1", "setAlpha"));
+ assertTrue(registry.matchesForCallStackDebugging("com.android.app2", "setAlpha"));
+
+ // Specific name, specific call
+ registry.setCallStackDebuggingParams("com.android.app1", "setAlpha");
+ assertFalse(registry.matchesForCallStackDebugging("com.android.app1", "setLayer"));
+ assertFalse(registry.matchesForCallStackDebugging("com.android.app2", "setAlpha"));
+ assertTrue(registry.matchesForCallStackDebugging("com.android.app1", "setAlpha"));
+ }
+
private SurfaceControl buildTestSurface() {
return new SurfaceControl.Builder()
.setContainerLayer()
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 1a38dec..6a9fc04 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -17,11 +17,6 @@
package android.view;
import static android.view.accessibility.Flags.FLAG_FORCE_INVERT_COLOR;
-import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE;
-import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
-import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
-import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
-import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
@@ -53,12 +48,8 @@
import android.os.Binder;
import android.os.SystemProperties;
import android.platform.test.annotations.Presubmit;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
@@ -106,10 +97,6 @@
// state after the test completes.
private static boolean sOriginalTouchMode;
- @Rule
- public final CheckFlagsRule mCheckFlagsRule =
- DeviceFlagsValueProvider.createCheckFlagsRule();
-
@BeforeClass
public static void setUpClass() {
sContext = sInstrumentation.getTargetContext();
@@ -440,129 +427,6 @@
assertThat(result).isFalse();
}
- /**
- * Test the default values are properly set
- */
- @UiThreadTest
- @Test
- @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE)
- public void votePreferredFrameRate_getDefaultValues() {
- ViewRootImpl viewRootImpl = new ViewRootImpl(sContext,
- sContext.getDisplayNoVerify());
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
- FRAME_RATE_CATEGORY_NO_PREFERENCE);
- assertEquals(viewRootImpl.getPreferredFrameRate(), 0, 0.1);
- }
-
- /**
- * Test the value of the frame rate cateogry based on the visibility of a view
- * Invsible: FRAME_RATE_CATEGORY_NO_PREFERENCE
- * Visible: FRAME_RATE_CATEGORY_NORMAL
- */
- @Test
- @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE)
- public void votePreferredFrameRate_voteFrameRateCategory_visibility() {
- View view = new View(sContext);
- attachViewToWindow(view);
- ViewRootImpl viewRootImpl = view.getViewRootImpl();
- sInstrumentation.runOnMainSync(() -> {
- view.setVisibility(View.INVISIBLE);
- view.invalidate();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
- FRAME_RATE_CATEGORY_NO_PREFERENCE);
- });
-
- sInstrumentation.runOnMainSync(() -> {
- view.setVisibility(View.VISIBLE);
- view.invalidate();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
- FRAME_RATE_CATEGORY_NORMAL);
- });
- }
-
- /**
- * Test the value of the frame rate cateogry based on the size of a view.
- * The current threshold value is 7% of the screen size
- * <7%: FRAME_RATE_CATEGORY_LOW
- */
- @Test
- @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE)
- public void votePreferredFrameRate_voteFrameRateCategory_smallSize() {
- View view = new View(sContext);
- WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
- wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
- wmlp.width = 1;
- wmlp.height = 1;
-
- sInstrumentation.runOnMainSync(() -> {
- WindowManager wm = sContext.getSystemService(WindowManager.class);
- wm.addView(view, wmlp);
- });
- sInstrumentation.waitForIdleSync();
-
- ViewRootImpl viewRootImpl = view.getViewRootImpl();
- sInstrumentation.runOnMainSync(() -> {
- view.invalidate();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW);
- });
- }
-
- /**
- * Test the value of the frame rate cateogry based on the size of a view.
- * The current threshold value is 7% of the screen size
- * >=7% : FRAME_RATE_CATEGORY_NORMAL
- */
- @Test
- @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE)
- public void votePreferredFrameRate_voteFrameRateCategory_normalSize() {
- View view = new View(sContext);
- WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
- wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
-
- sInstrumentation.runOnMainSync(() -> {
- WindowManager wm = sContext.getSystemService(WindowManager.class);
- Display display = wm.getDefaultDisplay();
- DisplayMetrics metrics = new DisplayMetrics();
- display.getMetrics(metrics);
- wmlp.width = (int) (metrics.widthPixels * 0.9);
- wmlp.height = (int) (metrics.heightPixels * 0.9);
- wm.addView(view, wmlp);
- });
- sInstrumentation.waitForIdleSync();
-
- ViewRootImpl viewRootImpl = view.getViewRootImpl();
- sInstrumentation.runOnMainSync(() -> {
- view.invalidate();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_NORMAL);
- });
- }
-
- /**
- * Test how values of the frame rate cateogry are aggregated.
- * It should take the max value among all of the voted categories per frame.
- */
- @Test
- @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE)
- public void votePreferredFrameRate_voteFrameRateCategory_aggregate() {
- View view = new View(sContext);
- attachViewToWindow(view);
- sInstrumentation.runOnMainSync(() -> {
- ViewRootImpl viewRootImpl = view.getViewRootImpl();
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
- FRAME_RATE_CATEGORY_NO_PREFERENCE);
- viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_LOW);
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW);
- viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_NORMAL);
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_NORMAL);
- viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_HIGH);
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
- viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_NORMAL);
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
- viewRootImpl.votePreferredFrameRateCategory(FRAME_RATE_CATEGORY_LOW);
- assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH);
- });
- }
-
@Test
public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() {
mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index b71aaf3..cc73ece 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2887,6 +2887,12 @@
"group": "WM_DEBUG_RESIZE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "419378610": {
+ "message": "Content Recording: Apply transformations of shift %d x %d, scale %f x %f, crop (aka recorded content size) %d x %d for display %d; display has size %d x %d; surface has size %d x %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"422634333": {
"message": "First draw done in potential wallpaper target %s",
"level": "VERBOSE",
@@ -4339,12 +4345,6 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
- "1936800105": {
- "message": "Content Recording: Apply transformations of shift %d x %d, scale %f, crop (aka recorded content size) %d x %d for display %d; display has size %d x %d; surface has size %d x %d",
- "level": "VERBOSE",
- "group": "WM_DEBUG_CONTENT_RECORDING",
- "at": "com\/android\/server\/wm\/ContentRecorder.java"
- },
"1945495497": {
"message": "Focused window didn't have a valid surface drawn.",
"level": "DEBUG",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 738c94e..79f306e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -19,6 +19,7 @@
import static android.view.View.LAYOUT_DIRECTION_RTL;
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
+import static com.android.wm.shell.bubbles.animation.FlingToDismissUtils.getFlingToDismissTargetWidth;
import android.content.res.Resources;
import android.graphics.Path;
@@ -375,6 +376,9 @@
mMagnetizedBubbleDraggingOut.setMagnetListener(listener);
mMagnetizedBubbleDraggingOut.setHapticsEnabled(true);
mMagnetizedBubbleDraggingOut.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
+ int screenWidthPx = mLayout.getContext().getResources().getDisplayMetrics().widthPixels;
+ mMagnetizedBubbleDraggingOut.setFlingToTargetWidthPercent(
+ getFlingToDismissTargetWidth(screenWidthPx));
}
private void springBubbleTo(View bubble, float x, float y) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/FlingToDismissUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/FlingToDismissUtils.kt
new file mode 100644
index 0000000..2a44f04
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/FlingToDismissUtils.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.bubbles.animation
+
+/** Utils related to the fling to dismiss animation. */
+object FlingToDismissUtils {
+
+ /** The target width surrounding the dismiss target on a small width screen, e.g. phone. */
+ private const val FLING_TO_DISMISS_TARGET_WIDTH_SMALL = 3f
+ /**
+ * The target width surrounding the dismiss target on a medium width screen, e.g. tablet in
+ * portrait.
+ */
+ private const val FLING_TO_DISMISS_TARGET_WIDTH_MEDIUM = 4.5f
+ /**
+ * The target width surrounding the dismiss target on a large width screen, e.g. tablet in
+ * landscape.
+ */
+ private const val FLING_TO_DISMISS_TARGET_WIDTH_LARGE = 6f
+
+ /** Returns the dismiss target width for the specified [screenWidthPx]. */
+ @JvmStatic
+ fun getFlingToDismissTargetWidth(screenWidthPx: Int) = when {
+ screenWidthPx >= 2000 -> FLING_TO_DISMISS_TARGET_WIDTH_LARGE
+ screenWidthPx >= 1500 -> FLING_TO_DISMISS_TARGET_WIDTH_MEDIUM
+ else -> FLING_TO_DISMISS_TARGET_WIDTH_SMALL
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index aad2683..e487328 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.bubbles.animation;
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
+import static com.android.wm.shell.bubbles.animation.FlingToDismissUtils.getFlingToDismissTargetWidth;
import android.content.ContentResolver;
import android.content.res.Resources;
@@ -851,6 +852,15 @@
if (mLayout != null) {
Resources res = mLayout.getContext().getResources();
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
+ updateFlingToDismissTargetWidth();
+ }
+ }
+
+ private void updateFlingToDismissTargetWidth() {
+ if (mLayout != null && mMagnetizedStack != null) {
+ int screenWidthPx = mLayout.getResources().getDisplayMetrics().widthPixels;
+ mMagnetizedStack.setFlingToTargetWidthPercent(
+ getFlingToDismissTargetWidth(screenWidthPx));
}
}
@@ -1022,23 +1032,8 @@
};
mMagnetizedStack.setHapticsEnabled(true);
mMagnetizedStack.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
+ updateFlingToDismissTargetWidth();
}
-
- final ContentResolver contentResolver = mLayout.getContext().getContentResolver();
- final float minVelocity = Settings.Secure.getFloat(contentResolver,
- "bubble_dismiss_fling_min_velocity",
- mMagnetizedStack.getFlingToTargetMinVelocity() /* default */);
- final float maxVelocity = Settings.Secure.getFloat(contentResolver,
- "bubble_dismiss_stick_max_velocity",
- mMagnetizedStack.getStickToTargetMaxXVelocity() /* default */);
- final float targetWidth = Settings.Secure.getFloat(contentResolver,
- "bubble_dismiss_target_width_percent",
- mMagnetizedStack.getFlingToTargetWidthPercent() /* default */);
-
- mMagnetizedStack.setFlingToTargetMinVelocity(minVelocity);
- mMagnetizedStack.setStickToTargetMaxXVelocity(maxVelocity);
- mMagnetizedStack.setFlingToTargetWidthPercent(targetWidth);
-
return mMagnetizedStack;
}
@@ -1053,7 +1048,7 @@
* property directly to move the first bubble and cause the stack to 'follow' to the new
* location.
*
- * This could also be achieved by simply animating the first bubble view and adding an update
+ * <p>This could also be achieved by simply animating the first bubble view and adding an update
* listener to dispatch movement to the rest of the stack. However, this would require
* duplication of logic in that update handler - it's simpler to keep all logic contained in the
* {@link #moveFirstBubbleWithStackFollowing} method.
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index e111edc..acfb259 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -220,19 +220,6 @@
}
android_test {
- name: "WMShellFlickerTestsPip",
- defaults: ["WMShellFlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestPip.xml"],
- package_name: "com.android.wm.shell.flicker.pip",
- instrumentation_target_package: "com.android.wm.shell.flicker.pip",
- srcs: [
- ":WMShellFlickerTestsBase-src",
- ":WMShellFlickerTestsPip3-src",
- ":WMShellFlickerTestsPipCommon-src",
- ],
-}
-
-android_test {
name: "WMShellFlickerTestsPip1",
defaults: ["WMShellFlickerTestsDefault"],
additional_manifests: ["manifests/AndroidManifestPip.xml"],
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 91fa873..cccf6f1 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -18,6 +18,9 @@
import static android.media.MediaRouter2Utils.toUniqueId;
+import static com.android.media.flags.Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER;
+
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -141,6 +144,8 @@
TYPE_WIRED_HEADPHONES,
TYPE_BLUETOOTH_A2DP,
TYPE_HDMI,
+ TYPE_HDMI_ARC,
+ TYPE_HDMI_EARC,
TYPE_USB_DEVICE,
TYPE_USB_ACCESSORY,
TYPE_DOCK,
@@ -206,6 +211,22 @@
public static final int TYPE_HDMI = AudioDeviceInfo.TYPE_HDMI;
/**
+ * Indicates the route is an Audio Return Channel of an HDMI connection.
+ *
+ * @see #getType
+ */
+ @FlaggedApi(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
+ public static final int TYPE_HDMI_ARC = AudioDeviceInfo.TYPE_HDMI_ARC;
+
+ /**
+ * Indicates the route is an Enhanced Audio Return Channel of an HDMI connection.
+ *
+ * @see #getType
+ */
+ @FlaggedApi(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
+ public static final int TYPE_HDMI_EARC = AudioDeviceInfo.TYPE_HDMI_EARC;
+
+ /**
* Indicates the route is a USB audio device.
*
* @see #getType
@@ -907,6 +928,10 @@
return "BLUETOOTH_A2DP";
case TYPE_HDMI:
return "HDMI";
+ case TYPE_HDMI_ARC:
+ return "HDMI_ARC";
+ case TYPE_HDMI_EARC:
+ return "HDMI_EARC";
case TYPE_DOCK:
return "DOCK";
case TYPE_USB_DEVICE:
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 159427b..76a00ac 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -310,8 +310,11 @@
IMediaRouterService.Stub.asInterface(
ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
+ mSystemController =
+ new SystemRoutingController(
+ ProxyMediaRouter2Impl.getSystemSessionInfoImpl(
+ mMediaRouterService, clientPackageName));
mImpl = new ProxyMediaRouter2Impl(context, clientPackageName);
- mSystemController = new SystemRoutingController(mImpl.getSystemSessionInfo());
}
/**
@@ -2057,13 +2060,7 @@
@Override
public RoutingSessionInfo getSystemSessionInfo() {
- RoutingSessionInfo result;
- try {
- result = mMediaRouterService.getSystemSessionInfoForPackage(mClientPackageName);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- return ensureClientPackageNameForSystemSession(result);
+ return getSystemSessionInfoImpl(mMediaRouterService, mClientPackageName);
}
/**
@@ -2428,6 +2425,23 @@
}
/**
+ * Retrieves the system session info for the given package.
+ *
+ * <p>The returned routing session is guaranteed to have a non-null {@link
+ * RoutingSessionInfo#getClientPackageName() client package name}.
+ *
+ * <p>Extracted into a static method to allow calling this from the constructor.
+ */
+ /* package */ static RoutingSessionInfo getSystemSessionInfoImpl(
+ @NonNull IMediaRouterService service, @NonNull String clientPackageName) {
+ try {
+ return service.getSystemSessionInfoForPackage(clientPackageName);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Sets the routing session's {@linkplain RoutingSessionInfo#getClientPackageName() client
* package name} to {@link #mClientPackageName} if empty and returns the session.
*
diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl
index 31e65eb..d0e860c 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -176,4 +176,21 @@
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
oneway void notifyPermissionRequestStateChange(int hostUid, int state, int sessionCreationSource);
+
+ /**
+ * Notifies system server that the permission request was initiated.
+ *
+ * <p>Only used for emitting atoms.
+ *
+ * @param hostUid The uid of the process requesting consent to capture, may be an app or
+ * SystemUI.
+ * @param sessionCreationSource Only set if the state is MEDIA_PROJECTION_STATE_INITIATED.
+ * Indicates the entry point for requesting the permission. Must be
+ * a valid state defined
+ * in the SessionCreationSource enum.
+ */
+ @EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION")
+ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ + ".permission.MANAGE_MEDIA_PROJECTION)")
+ oneway void notifyPermissionRequestInitiated(int hostUid, int sessionCreationSource);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
index e38e041..2a28417 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/DeviceIconUtil.java
@@ -39,39 +39,50 @@
@DrawableRes private static final int DEFAULT_ICON = R.drawable.ic_smartphone;
public DeviceIconUtil() {
- List<Device> deviceList = Arrays.asList(
- new Device(
- AudioDeviceInfo.TYPE_USB_DEVICE,
- MediaRoute2Info.TYPE_USB_DEVICE,
- R.drawable.ic_headphone),
- new Device(
- AudioDeviceInfo.TYPE_USB_HEADSET,
- MediaRoute2Info.TYPE_USB_HEADSET,
- R.drawable.ic_headphone),
- new Device(
- AudioDeviceInfo.TYPE_USB_ACCESSORY,
- MediaRoute2Info.TYPE_USB_ACCESSORY,
- R.drawable.ic_headphone),
- new Device(
- AudioDeviceInfo.TYPE_DOCK,
- MediaRoute2Info.TYPE_DOCK,
- R.drawable.ic_dock_device),
- new Device(
- AudioDeviceInfo.TYPE_HDMI,
- MediaRoute2Info.TYPE_HDMI,
- R.drawable.ic_headphone),
- new Device(
- AudioDeviceInfo.TYPE_WIRED_HEADSET,
- MediaRoute2Info.TYPE_WIRED_HEADSET,
- R.drawable.ic_headphone),
- new Device(
- AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
- MediaRoute2Info.TYPE_WIRED_HEADPHONES,
- R.drawable.ic_headphone),
- new Device(
- AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
- MediaRoute2Info.TYPE_BUILTIN_SPEAKER,
- R.drawable.ic_smartphone));
+ List<Device> deviceList =
+ Arrays.asList(
+ new Device(
+ AudioDeviceInfo.TYPE_USB_DEVICE,
+ MediaRoute2Info.TYPE_USB_DEVICE,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_USB_HEADSET,
+ MediaRoute2Info.TYPE_USB_HEADSET,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_USB_ACCESSORY,
+ MediaRoute2Info.TYPE_USB_ACCESSORY,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_DOCK,
+ MediaRoute2Info.TYPE_DOCK,
+ R.drawable.ic_dock_device),
+ new Device(
+ AudioDeviceInfo.TYPE_HDMI,
+ MediaRoute2Info.TYPE_HDMI,
+ R.drawable.ic_headphone),
+ // TODO: b/306359110 - Put proper iconography for HDMI_ARC type.
+ new Device(
+ AudioDeviceInfo.TYPE_HDMI_ARC,
+ MediaRoute2Info.TYPE_HDMI_ARC,
+ R.drawable.ic_headphone),
+ // TODO: b/306359110 - Put proper iconography for HDMI_EARC type.
+ new Device(
+ AudioDeviceInfo.TYPE_HDMI_EARC,
+ MediaRoute2Info.TYPE_HDMI_EARC,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_WIRED_HEADSET,
+ MediaRoute2Info.TYPE_WIRED_HEADSET,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
+ MediaRoute2Info.TYPE_WIRED_HEADPHONES,
+ R.drawable.ic_headphone),
+ new Device(
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
+ MediaRoute2Info.TYPE_BUILTIN_SPEAKER,
+ R.drawable.ic_smartphone));
for (int i = 0; i < deviceList.size(); i++) {
Device device = deviceList.get(i);
mAudioDeviceTypeToIconMap.put(device.mAudioDeviceType, device);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index bf63f5d..5dacba5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -21,6 +21,8 @@
import static android.media.MediaRoute2Info.TYPE_DOCK;
import static android.media.MediaRoute2Info.TYPE_GROUP;
import static android.media.MediaRoute2Info.TYPE_HDMI;
+import static android.media.MediaRoute2Info.TYPE_HDMI_ARC;
+import static android.media.MediaRoute2Info.TYPE_HDMI_EARC;
import static android.media.MediaRoute2Info.TYPE_HEARING_AID;
import static android.media.MediaRoute2Info.TYPE_REMOTE_AUDIO_VIDEO_RECEIVER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_CAR;
@@ -635,6 +637,8 @@
case TYPE_USB_ACCESSORY:
case TYPE_DOCK:
case TYPE_HDMI:
+ case TYPE_HDMI_ARC:
+ case TYPE_HDMI_EARC:
case TYPE_WIRED_HEADSET:
case TYPE_WIRED_HEADPHONES:
mediaDevice =
@@ -668,11 +672,12 @@
route,
mPackageName,
mPreferenceItemMap.get(route.getId()));
+ break;
default:
Log.w(TAG, "addMediaDevice() unknown device type : " + deviceType);
break;
-
}
+
if (mediaDevice != null && !TextUtils.isEmpty(mPackageName)
&& getRoutingSessionInfo().getSelectedRoutes().contains(route.getId())) {
mediaDevice.setState(STATE_SELECTED);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 147412d..8085c99 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -21,6 +21,8 @@
import static android.media.MediaRoute2Info.TYPE_DOCK;
import static android.media.MediaRoute2Info.TYPE_GROUP;
import static android.media.MediaRoute2Info.TYPE_HDMI;
+import static android.media.MediaRoute2Info.TYPE_HDMI_ARC;
+import static android.media.MediaRoute2Info.TYPE_HDMI_EARC;
import static android.media.MediaRoute2Info.TYPE_HEARING_AID;
import static android.media.MediaRoute2Info.TYPE_REMOTE_AUDIO_VIDEO_RECEIVER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
@@ -140,7 +142,6 @@
mType = MediaDeviceType.TYPE_BLUETOOTH_DEVICE;
return;
}
-
switch (info.getType()) {
case TYPE_GROUP:
mType = MediaDeviceType.TYPE_CAST_GROUP_DEVICE;
@@ -157,6 +158,8 @@
case TYPE_USB_ACCESSORY:
case TYPE_DOCK:
case TYPE_HDMI:
+ case TYPE_HDMI_ARC:
+ case TYPE_HDMI_EARC:
mType = MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE;
break;
case TYPE_HEARING_AID:
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index a63bbdf..c44f66e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -18,6 +18,8 @@
import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_DOCK;
import static android.media.MediaRoute2Info.TYPE_HDMI;
+import static android.media.MediaRoute2Info.TYPE_HDMI_ARC;
+import static android.media.MediaRoute2Info.TYPE_HDMI_EARC;
import static android.media.MediaRoute2Info.TYPE_USB_ACCESSORY;
import static android.media.MediaRoute2Info.TYPE_USB_DEVICE;
import static android.media.MediaRoute2Info.TYPE_USB_HEADSET;
@@ -71,6 +73,8 @@
name = context.getString(R.string.media_transfer_this_device_name);
break;
case TYPE_HDMI:
+ case TYPE_HDMI_ARC:
+ case TYPE_HDMI_EARC:
name = context.getString(R.string.media_transfer_external_device_name);
break;
default:
@@ -144,6 +148,8 @@
case TYPE_USB_ACCESSORY:
case TYPE_DOCK:
case TYPE_HDMI:
+ case TYPE_HDMI_ARC:
+ case TYPE_HDMI_EARC:
id = USB_HEADSET_ID;
break;
case TYPE_BUILTIN_SPEAKER:
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig
index 0f55f35..eadcd7c 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig
@@ -1,15 +1,17 @@
package: "com.android.systemui.accessibility.accessibilitymenu"
-flag {
- name: "a11y_menu_settings_back_button_fix_and_large_button_sizing"
- namespace: "accessibility"
- description: "Provides/restores back button functionality for the a11yMenu settings page. Also, fixes sizing problems with large shortcut buttons."
- bug: "298467628"
-}
+# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
flag {
name: "a11y_menu_hide_before_taking_action"
namespace: "accessibility"
description: "Hides the AccessibilityMenuService UI before taking action instead of after."
bug: "292020123"
-}
\ No newline at end of file
+}
+
+flag {
+ name: "a11y_menu_settings_back_button_fix_and_large_button_sizing"
+ namespace: "accessibility"
+ description: "Provides/restores back button functionality for the a11yMenu settings page. Also, fixes sizing problems with large shortcut buttons."
+ bug: "298467628"
+}
diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig
index 8841967..bcf1535 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -1,5 +1,7 @@
package: "com.android.systemui"
+# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
+
flag {
name: "floating_menu_overlaps_nav_bars_flag"
namespace: "accessibility"
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 211af90..0567528 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -31,6 +31,13 @@
}
flag {
+ name: "notification_async_hybrid_view_inflation"
+ namespace: "systemui"
+ description: "Inflates the hybrid (single-line) notification views form the background thread."
+ bug: "217799515"
+}
+
+flag {
name: "scene_container"
namespace: "systemui"
description: "Enables the scene container framework go/flexiglass."
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
index 6c4b695..af35ea4 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
@@ -68,6 +68,7 @@
override var launchContainer = ghostedView.rootView as ViewGroup
private val launchContainerOverlay: ViewGroupOverlay
get() = launchContainer.overlay
+
private val launchContainerLocation = IntArray(2)
/** The ghost view that is drawn and animated instead of the ghosted view. */
@@ -206,9 +207,8 @@
return
}
- backgroundView = FrameLayout(launchContainer.context).also {
- launchContainerOverlay.add(it)
- }
+ backgroundView =
+ FrameLayout(launchContainer.context).also { launchContainerOverlay.add(it) }
// We wrap the ghosted view background and use it to draw the expandable background. Its
// alpha will be set to 0 as soon as we start drawing the expanding background.
@@ -226,6 +226,17 @@
// the content before fading out the background.
ghostView = GhostView.addGhost(ghostedView, launchContainer)
+ // [GhostView.addGhost], the result of which is our [ghostView], creates a [GhostView], and
+ // adds it first to a [FrameLayout] container. It then adds _that_ container to an
+ // [OverlayViewGroup]. We need to turn off clipping for that container view. Currently,
+ // however, the only way to get a reference to that overlay is by going through our
+ // [ghostView]. The [OverlayViewGroup] will always be its grandparent view.
+ // TODO(b/306652954) reference the overlay view group directly if we can
+ (ghostView?.parent?.parent as? ViewGroup)?.let {
+ it.clipChildren = false
+ it.clipToPadding = false
+ }
+
val matrix = ghostView?.animationMatrix ?: Matrix.IDENTITY_MATRIX
matrix.getValues(initialGhostViewMatrixValues)
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 5a70b79..452bc31 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -66,7 +66,7 @@
<FrameLayout
android:id="@+id/status_bar_start_side_content"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="center_vertical|start"
android:clipChildren="false">
@@ -77,7 +77,7 @@
and DISABLE_NOTIFICATION_ICONS, respectively -->
<LinearLayout
android:id="@+id/status_bar_start_side_except_heads_up"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_gravity="center_vertical|start"
android:clipChildren="false">
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 8957903..7e03bd9 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -26,24 +26,6 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">
- <com.android.systemui.statusbar.BackDropView
- android:id="@+id/backdrop"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"
- sysui:ignoreRightInset="true"
- >
- <ImageView android:id="@+id/backdrop_back"
- android:layout_width="match_parent"
- android:scaleType="centerCrop"
- android:layout_height="match_parent" />
- <ImageView android:id="@+id/backdrop_front"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="centerCrop"
- android:visibility="invisible" />
- </com.android.systemui.statusbar.BackDropView>
-
<com.android.systemui.scrim.ScrimView
android:id="@+id/scrim_behind"
android:layout_width="match_parent"
@@ -63,7 +45,8 @@
<com.android.systemui.statusbar.LightRevealScrim
android:id="@+id/light_reveal_scrim"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ sysui:ignoreRightInset="true" />
<include layout="@layout/status_bar_expanded"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 587caaf..db526b1 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -46,4 +46,7 @@
For now, this value has effect only when flag lockscreen.enable_landscape is enabled.
TODO (b/293252410) - change this comment/resource when flag is enabled -->
<bool name="force_config_use_split_notification_shade">true</bool>
+
+ <!-- Whether to show bottom sheets edge to edge -->
+ <bool name="config_edgeToEdgeBottomSheetDialog">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7a6d29a..9e2ebf6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3224,6 +3224,9 @@
<!--- Label of the dismiss button of the dialog appearing when an external display is connected [CHAR LIMIT=NONE]-->
<string name="dismiss_dialog">Dismiss</string>
+ <!--- Content description of the connected display status bar icon that appears every time a display is connected [CHAR LIMIT=NONE]-->
+ <string name="connected_display_icon_desc">Display connected</string>
+
<!-- Title of the privacy dialog, shown for active / recent app usage of some phone sensors [CHAR LIMIT=30] -->
<string name="privacy_dialog_title">Microphone & Camera</string>
<!-- Subtitle of the privacy dialog, shown for active / recent app usage of some phone sensors [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateRepository.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateRepository.kt
new file mode 100644
index 0000000..f219cec
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateRepository.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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.unfold.system
+
+import com.android.systemui.unfold.dagger.UnfoldMain
+import com.android.systemui.unfold.updates.FoldProvider
+import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.buffer
+import kotlinx.coroutines.flow.callbackFlow
+
+/** Provides whether the device is folded. */
+interface DeviceStateRepository {
+ val isFolded: Flow<Boolean>
+}
+
+@Singleton
+class DeviceStateRepositoryImpl
+@Inject
+constructor(
+ private val foldProvider: FoldProvider,
+ @UnfoldMain private val executor: Executor,
+) : DeviceStateRepository {
+
+ override val isFolded: Flow<Boolean>
+ get() =
+ callbackFlow {
+ val callback = FoldCallback { isFolded -> trySend(isFolded) }
+ foldProvider.registerCallback(callback, executor)
+ awaitClose { foldProvider.unregisterCallback(callback) }
+ }
+ .buffer(capacity = Channel.CONFLATED)
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt
index fe607e1..7b67e3f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt
@@ -48,6 +48,9 @@
abstract fun foldState(provider: DeviceStateManagerFoldProvider): FoldProvider
@Binds
+ abstract fun deviceStateRepository(provider: DeviceStateRepositoryImpl): DeviceStateRepository
+
+ @Binds
@UnfoldMain
abstract fun mainExecutor(@Main executor: Executor): Executor
diff --git a/packages/SystemUI/shared/src/com/android/systemui/util/TraceStateLogger.kt b/packages/SystemUI/shared/src/com/android/systemui/util/TraceStateLogger.kt
new file mode 100644
index 0000000..63ea116
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/util/TraceStateLogger.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 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.util
+
+import android.os.Trace
+
+/**
+ * Utility class used to log state changes easily in a track with a custom name.
+ *
+ * Example of usage:
+ * ```kotlin
+ * class MyClass {
+ * val screenStateLogger = TraceStateLogger("Screen state")
+ *
+ * fun onTurnedOn() { screenStateLogger.log("on") }
+ * fun onTurnedOff() { screenStateLogger.log("off") }
+ * }
+ * ```
+ *
+ * This creates a new slice in a perfetto trace only if the state is different than the previous
+ * one.
+ */
+class TraceStateLogger(
+ private val trackName: String,
+ private val logOnlyIfDifferent: Boolean = true,
+ private val instantEvent: Boolean = true
+) {
+
+ private var previousValue: String? = null
+
+ /** If needed, logs the value to a track with name [trackName]. */
+ fun log(newValue: String) {
+ if (instantEvent) {
+ Trace.instantForTrack(Trace.TRACE_TAG_APP, trackName, newValue)
+ }
+ if (logOnlyIfDifferent && previousValue == newValue) return
+ Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, trackName, 0)
+ Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, trackName, newValue, 0)
+ previousValue = newValue
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java
index fd84543..494efb7 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java
@@ -25,21 +25,24 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
+import android.content.res.Resources;
import android.os.UserHandle;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.qs.QSUserSwitcherEvent;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.UserSwitcherController;
-import javax.inject.Inject;
-
+import dagger.Lazy;
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
+import javax.inject.Inject;
+
/**
* Manages handling of guest session persistent notification
* and actions to reset guest or exit guest session
@@ -70,14 +73,14 @@
public AlertDialog mResetSessionDialog;
private final UserTracker mUserTracker;
private final BroadcastDispatcher mBroadcastDispatcher;
- private final ResetSessionDialog.Factory mResetSessionDialogFactory;
- private final ExitSessionDialog.Factory mExitSessionDialogFactory;
+ private final ResetSessionDialogFactory mResetSessionDialogFactory;
+ private final ExitSessionDialogFactory mExitSessionDialogFactory;
@Inject
public GuestResetOrExitSessionReceiver(UserTracker userTracker,
BroadcastDispatcher broadcastDispatcher,
- ResetSessionDialog.Factory resetSessionDialogFactory,
- ExitSessionDialog.Factory exitSessionDialogFactory) {
+ ResetSessionDialogFactory resetSessionDialogFactory,
+ ExitSessionDialogFactory exitSessionDialogFactory) {
mUserTracker = userTracker;
mBroadcastDispatcher = broadcastDispatcher;
mResetSessionDialogFactory = resetSessionDialogFactory;
@@ -111,8 +114,8 @@
mResetSessionDialog = mResetSessionDialogFactory.create(currentUser.id);
mResetSessionDialog.show();
} else if (ACTION_GUEST_EXIT.equals(action)) {
- mExitSessionDialog = mExitSessionDialogFactory.create(currentUser.id,
- currentUser.isEphemeral());
+ mExitSessionDialog = mExitSessionDialogFactory.create(
+ currentUser.isEphemeral(), currentUser.id);
mExitSessionDialog.show();
}
}
@@ -132,43 +135,69 @@
}
/**
+ * Factory class to create guest reset dialog instance
+ *
* Dialog shown when asking for confirmation before
* reset and restart of guest user.
*/
- public static final class ResetSessionDialog extends SystemUIDialog implements
- DialogInterface.OnClickListener {
+ public static final class ResetSessionDialogFactory {
+ private final Lazy<SystemUIDialog> mDialogLazy;
+ private final Resources mResources;
+ private final ResetSessionDialogClickListener.Factory mClickListenerFactory;
+ @Inject
+ public ResetSessionDialogFactory(
+ Lazy<SystemUIDialog> dialogLazy,
+ @Main Resources resources,
+ ResetSessionDialogClickListener.Factory clickListenerFactory) {
+ mDialogLazy = dialogLazy;
+ mResources = resources;
+ mClickListenerFactory = clickListenerFactory;
+ }
+
+ /** Create a guest reset dialog instance */
+ public AlertDialog create(int userId) {
+ SystemUIDialog dialog = mDialogLazy.get();
+ ResetSessionDialogClickListener listener = mClickListenerFactory.create(
+ userId, dialog);
+ dialog.setTitle(com.android.settingslib.R.string.guest_reset_and_restart_dialog_title);
+ dialog.setMessage(mResources.getString(
+ com.android.settingslib.R.string.guest_reset_and_restart_dialog_message));
+ dialog.setButton(
+ DialogInterface.BUTTON_NEUTRAL,
+ mResources.getString(android.R.string.cancel),
+ listener);
+ dialog.setButton(DialogInterface.BUTTON_POSITIVE,
+ mResources.getString(
+ com.android.settingslib.R.string.guest_reset_guest_confirm_button),
+ listener);
+ dialog.setCanceledOnTouchOutside(false);
+ return dialog;
+ }
+ }
+
+ public static class ResetSessionDialogClickListener implements DialogInterface.OnClickListener {
private final UserSwitcherController mUserSwitcherController;
private final UiEventLogger mUiEventLogger;
private final int mUserId;
+ private final DialogInterface mDialog;
- /** Factory class to create guest reset dialog instance */
@AssistedFactory
public interface Factory {
- /** Create a guest reset dialog instance */
- ResetSessionDialog create(int userId);
+ ResetSessionDialogClickListener create(int userId, DialogInterface dialog);
}
@AssistedInject
- ResetSessionDialog(Context context,
+ public ResetSessionDialogClickListener(
UserSwitcherController userSwitcherController,
UiEventLogger uiEventLogger,
- @Assisted int userId) {
- super(context);
-
- setTitle(com.android.settingslib.R.string.guest_reset_and_restart_dialog_title);
- setMessage(context.getString(
- com.android.settingslib.R.string.guest_reset_and_restart_dialog_message));
- setButton(DialogInterface.BUTTON_NEUTRAL,
- context.getString(android.R.string.cancel), this);
- setButton(DialogInterface.BUTTON_POSITIVE,
- context.getString(
- com.android.settingslib.R.string.guest_reset_guest_confirm_button), this);
- setCanceledOnTouchOutside(false);
-
+ @Assisted int userId,
+ @Assisted DialogInterface dialog
+ ) {
mUserSwitcherController = userSwitcherController;
mUiEventLogger = uiEventLogger;
mUserId = userId;
+ mDialog = dialog;
}
@Override
@@ -177,7 +206,7 @@
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE);
mUserSwitcherController.removeGuestUser(mUserId, UserHandle.USER_NULL);
} else if (which == DialogInterface.BUTTON_NEUTRAL) {
- cancel();
+ mDialog.cancel();
}
}
}
@@ -186,58 +215,93 @@
* Dialog shown when asking for confirmation before
* exit of guest user.
*/
- public static final class ExitSessionDialog extends SystemUIDialog implements
- DialogInterface.OnClickListener {
+ public static final class ExitSessionDialogFactory {
+ private final Lazy<SystemUIDialog> mDialogLazy;
+ private final ExitSessionDialogClickListener.Factory mClickListenerFactory;
+ private final Resources mResources;
+ @Inject
+ public ExitSessionDialogFactory(
+ Lazy<SystemUIDialog> dialogLazy,
+ ExitSessionDialogClickListener.Factory clickListenerFactory,
+ @Main Resources resources) {
+ mDialogLazy = dialogLazy;
+ mClickListenerFactory = clickListenerFactory;
+ mResources = resources;
+ }
+
+ public AlertDialog create(boolean isEphemeral, int userId) {
+ SystemUIDialog dialog = mDialogLazy.get();
+ ExitSessionDialogClickListener clickListener = mClickListenerFactory.create(
+ isEphemeral, userId, dialog);
+ if (isEphemeral) {
+ dialog.setTitle(mResources.getString(
+ com.android.settingslib.R.string.guest_exit_dialog_title));
+ dialog.setMessage(mResources.getString(
+ com.android.settingslib.R.string.guest_exit_dialog_message));
+ dialog.setButton(
+ DialogInterface.BUTTON_NEUTRAL,
+ mResources.getString(android.R.string.cancel),
+ clickListener);
+ dialog.setButton(
+ DialogInterface.BUTTON_POSITIVE,
+ mResources.getString(
+ com.android.settingslib.R.string.guest_exit_dialog_button),
+ clickListener);
+ } else {
+ dialog.setTitle(mResources.getString(
+ com.android.settingslib
+ .R.string.guest_exit_dialog_title_non_ephemeral));
+ dialog.setMessage(mResources.getString(
+ com.android.settingslib
+ .R.string.guest_exit_dialog_message_non_ephemeral));
+ dialog.setButton(
+ DialogInterface.BUTTON_NEUTRAL,
+ mResources.getString(android.R.string.cancel),
+ clickListener);
+ dialog.setButton(
+ DialogInterface.BUTTON_NEGATIVE,
+ mResources.getString(
+ com.android.settingslib.R.string.guest_exit_clear_data_button),
+ clickListener);
+ dialog.setButton(
+ DialogInterface.BUTTON_POSITIVE,
+ mResources.getString(
+ com.android.settingslib.R.string.guest_exit_save_data_button),
+ clickListener);
+ }
+ dialog.setCanceledOnTouchOutside(false);
+
+ return dialog;
+ }
+
+ }
+
+ public static class ExitSessionDialogClickListener implements DialogInterface.OnClickListener {
private final UserSwitcherController mUserSwitcherController;
+ private final boolean mIsEphemeral;
private final int mUserId;
- private boolean mIsEphemeral;
+ private final DialogInterface mDialog;
- /** Factory class to create guest exit dialog instance */
@AssistedFactory
public interface Factory {
- /** Create a guest exit dialog instance */
- ExitSessionDialog create(int userId, boolean isEphemeral);
+ ExitSessionDialogClickListener create(
+ boolean isEphemeral,
+ int userId,
+ DialogInterface dialog);
}
@AssistedInject
- ExitSessionDialog(Context context,
+ public ExitSessionDialogClickListener(
UserSwitcherController userSwitcherController,
+ @Assisted boolean isEphemeral,
@Assisted int userId,
- @Assisted boolean isEphemeral) {
- super(context);
-
- if (isEphemeral) {
- setTitle(context.getString(
- com.android.settingslib.R.string.guest_exit_dialog_title));
- setMessage(context.getString(
- com.android.settingslib.R.string.guest_exit_dialog_message));
- setButton(DialogInterface.BUTTON_NEUTRAL,
- context.getString(android.R.string.cancel), this);
- setButton(DialogInterface.BUTTON_POSITIVE,
- context.getString(
- com.android.settingslib.R.string.guest_exit_dialog_button), this);
- } else {
- setTitle(context.getString(
- com.android.settingslib
- .R.string.guest_exit_dialog_title_non_ephemeral));
- setMessage(context.getString(
- com.android.settingslib
- .R.string.guest_exit_dialog_message_non_ephemeral));
- setButton(DialogInterface.BUTTON_NEUTRAL,
- context.getString(android.R.string.cancel), this);
- setButton(DialogInterface.BUTTON_NEGATIVE,
- context.getString(
- com.android.settingslib.R.string.guest_exit_clear_data_button), this);
- setButton(DialogInterface.BUTTON_POSITIVE,
- context.getString(
- com.android.settingslib.R.string.guest_exit_save_data_button), this);
- }
- setCanceledOnTouchOutside(false);
-
+ @Assisted DialogInterface dialog
+ ) {
mUserSwitcherController = userSwitcherController;
- mUserId = userId;
mIsEphemeral = isEphemeral;
+ mUserId = userId;
+ mDialog = dialog;
}
@Override
@@ -249,7 +313,7 @@
mUserSwitcherController.exitGuestUser(mUserId, UserHandle.USER_NULL, false);
} else if (which == DialogInterface.BUTTON_NEUTRAL) {
// Cancel clicked, do nothing
- cancel();
+ mDialog.cancel();
}
} else {
if (which == DialogInterface.BUTTON_POSITIVE) {
@@ -261,7 +325,7 @@
mUserSwitcherController.exitGuestUser(mUserId, UserHandle.USER_NULL, true);
} else if (which == DialogInterface.BUTTON_NEUTRAL) {
// Cancel clicked, do nothing
- cancel();
+ mDialog.cancel();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index b573fad..0f5f869 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -27,6 +27,7 @@
import com.android.systemui.res.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.GuestResetOrExitSessionReceiver.ResetSessionDialogFactory;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -36,14 +37,14 @@
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.settings.SecureSettings;
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
/**
* Manages notification when a guest session is resumed.
*/
@@ -58,7 +59,7 @@
private final Executor mMainExecutor;
private final UserTracker mUserTracker;
private final SecureSettings mSecureSettings;
- private final ResetSessionDialog.Factory mResetSessionDialogFactory;
+ private final ResetSessionDialogFactory mResetSessionDialogFactory;
private final GuestSessionNotification mGuestSessionNotification;
@VisibleForTesting
@@ -104,7 +105,7 @@
UserTracker userTracker,
SecureSettings secureSettings,
GuestSessionNotification guestSessionNotification,
- ResetSessionDialog.Factory resetSessionDialogFactory) {
+ ResetSessionDialogFactory resetSessionDialogFactory) {
mMainExecutor = mainExecutor;
mUserTracker = userTracker;
mSecureSettings = secureSettings;
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index 0bf5069..7d73896 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -19,7 +19,6 @@
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.Context;
-import android.graphics.Color;
import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
@@ -47,9 +46,7 @@
ConfigurationController.ConfigurationListener {
private static final String TAG = "SysuiColorExtractor";
private final Tonal mTonal;
- private boolean mHasMediaArtwork;
private final GradientColors mNeutralColorsLock;
- private final GradientColors mBackdropColors;
private Lazy<SelectedUserInteractor> mUserInteractor;
@Inject
@@ -82,9 +79,6 @@
mNeutralColorsLock = new GradientColors();
configurationController.addCallback(this);
dumpManager.registerDumpable(getClass().getSimpleName(), this);
-
- mBackdropColors = new GradientColors();
- mBackdropColors.setMainColor(Color.BLACK);
mUserInteractor = userInteractor;
// Listen to all users instead of only the current one.
@@ -123,14 +117,6 @@
triggerColorsChanged(WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
}
- @Override
- public GradientColors getColors(int which, int type) {
- if (mHasMediaArtwork && (which & WallpaperManager.FLAG_LOCK) != 0) {
- return mBackdropColors;
- }
- return super.getColors(which, type);
- }
-
/**
* Colors that should be using for scrims.
*
@@ -140,14 +126,7 @@
* - Black otherwise
*/
public GradientColors getNeutralColors() {
- return mHasMediaArtwork ? mBackdropColors : mNeutralColorsLock;
- }
-
- public void setHasMediaArtwork(boolean hasBackdrop) {
- if (mHasMediaArtwork != hasBackdrop) {
- mHasMediaArtwork = hasBackdrop;
- triggerColorsChanged(WallpaperManager.FLAG_LOCK);
- }
+ return mNeutralColorsLock;
}
@Override
@@ -164,7 +143,5 @@
pw.println(" system: " + Arrays.toString(system));
pw.println(" lock: " + Arrays.toString(lock));
pw.println(" Neutral colors: " + mNeutralColorsLock);
- pw.println(" Has media backdrop: " + mHasMediaArtwork);
-
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 5d6949b..d8ff535 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -57,7 +57,6 @@
import com.android.systemui.statusbar.gesture.GesturePointerEventListener
import com.android.systemui.statusbar.notification.InstantAppNotifier
import com.android.systemui.statusbar.phone.KeyguardLiftController
-import com.android.systemui.statusbar.phone.LockscreenWallpaper
import com.android.systemui.statusbar.phone.ScrimController
import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener
import com.android.systemui.stylus.StylusUsiPowerStartable
@@ -344,11 +343,6 @@
@Binds
@IntoMap
- @ClassKey(LockscreenWallpaper::class)
- abstract fun bindLockscreenWallpaper(impl: LockscreenWallpaper): CoreStartable
-
- @Binds
- @IntoMap
@ClassKey(ScrimController::class)
abstract fun bindScrimController(impl: ScrimController): CoreStartable
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
index d19efbd..3f21533 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
@@ -21,6 +21,7 @@
import android.widget.TextView
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIBottomSheetDialog
+import com.android.systemui.statusbar.policy.ConfigurationController
/**
* Dialog used to decide what to do with a connected display.
@@ -32,8 +33,9 @@
context: Context,
private val onStartMirroringClickListener: View.OnClickListener,
private val onCancelMirroring: View.OnClickListener,
+ configurationController: ConfigurationController? = null,
theme: Int = R.style.Theme_SystemUI_Dialog,
-) : SystemUIBottomSheetDialog(context, theme) {
+) : SystemUIBottomSheetDialog(context, configurationController, theme) {
private lateinit var mirrorButton: TextView
private lateinit var dismissButton: TextView
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
index 86ef439..91f535d 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
@@ -23,6 +23,7 @@
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
import com.android.systemui.display.ui.view.MirroringConfirmationDialog
+import com.android.systemui.statusbar.policy.ConfigurationController
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -41,7 +42,8 @@
private val context: Context,
private val connectedDisplayInteractor: ConnectedDisplayInteractor,
@Application private val scope: CoroutineScope,
- @Background private val bgDispatcher: CoroutineDispatcher
+ @Background private val bgDispatcher: CoroutineDispatcher,
+ private val configurationController: ConfigurationController
) {
private var dialog: Dialog? = null
@@ -71,7 +73,8 @@
onCancelMirroring = {
scope.launch(bgDispatcher) { pendingDisplay.ignore() }
hideDialog()
- }
+ },
+ configurationController
)
.apply { show() }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index c91c9ac..10fac4d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -549,12 +549,6 @@
val LOCKSCREEN_ENABLE_LANDSCAPE =
unreleasedFlag("lockscreen.enable_landscape")
- // TODO(b/273443374): Tracking Bug
- @Keep
- @JvmField
- val LOCKSCREEN_LIVE_WALLPAPER =
- sysPropBooleanFlag("persist.wm.debug.lockscreen_live_wallpaper", default = true)
-
// TODO(b/281648899): Tracking bug
@Keep
@JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 4779895..2b1cdc2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -202,7 +202,7 @@
// Wrap Keyguard going away animation.
// Note: Also used for wrapping occlude by Dream animation. It works (with some redundancy).
public static IRemoteTransition wrap(final KeyguardViewMediator keyguardViewMediator,
- final IRemoteAnimationRunner runner, final boolean lockscreenLiveWallpaperEnabled) {
+ final IRemoteAnimationRunner runner) {
return new IRemoteTransition.Stub() {
@GuardedBy("mLeashMap")
@@ -236,9 +236,8 @@
}
}
initAlphaForAnimationTargets(t, apps);
- if (lockscreenLiveWallpaperEnabled) {
- initAlphaForAnimationTargets(t, wallpapers);
- }
+ initAlphaForAnimationTargets(t, wallpapers);
+
t.apply();
runner.onAnimationStart(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 0bac40b..c8c06ae 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -707,8 +707,7 @@
return@postDelayed
}
- if ((wallpaperTargets?.isNotEmpty() == true) &&
- wallpaperManager.isLockscreenLiveWallpaperEnabled()) {
+ if ((wallpaperTargets?.isNotEmpty() == true)) {
fadeInWallpaper()
hideKeyguardViewAfterRemoteAnimation()
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e893c63..4e6a872 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -184,8 +184,6 @@
import java.util.concurrent.Executor;
import java.util.function.Consumer;
-
-
import kotlinx.coroutines.CoroutineDispatcher;
/**
@@ -1517,12 +1515,11 @@
setShowingLocked(false /* showing */, true /* forceCallbacks */);
}
- boolean isLLwpEnabled = getWallpaperManager().isLockscreenLiveWallpaperEnabled();
mKeyguardTransitions.register(
- KeyguardService.wrap(this, getExitAnimationRunner(), isLLwpEnabled),
- KeyguardService.wrap(this, getOccludeAnimationRunner(), isLLwpEnabled),
- KeyguardService.wrap(this, getOccludeByDreamAnimationRunner(), isLLwpEnabled),
- KeyguardService.wrap(this, getUnoccludeAnimationRunner(), isLLwpEnabled));
+ KeyguardService.wrap(this, getExitAnimationRunner()),
+ KeyguardService.wrap(this, getOccludeAnimationRunner()),
+ KeyguardService.wrap(this, getOccludeByDreamAnimationRunner()),
+ KeyguardService.wrap(this, getUnoccludeAnimationRunner()));
final ContentResolver cr = mContext.getContentResolver();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index d06f31f..7e360cf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -26,13 +26,13 @@
import com.android.systemui.util.kotlin.Utils.Companion.toQuint
import com.android.systemui.util.kotlin.sample
import com.android.wm.shell.animation.Interpolators
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
-import javax.inject.Inject
-import kotlin.time.Duration.Companion.milliseconds
@SysUISingleton
class FromAlternateBouncerTransitionInteractor
@@ -130,11 +130,16 @@
override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
interpolator = Interpolators.LINEAR
- duration = TRANSITION_DURATION_MS.inWholeMilliseconds
+ duration =
+ when (toState) {
+ KeyguardState.GONE -> TO_GONE_DURATION
+ else -> TRANSITION_DURATION_MS
+ }.inWholeMilliseconds
}
}
companion object {
val TRANSITION_DURATION_MS = 300.milliseconds
+ val TO_GONE_DURATION = 500.milliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index fbe26de..b0b8577 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -143,6 +143,11 @@
val dozingToLockscreenTransition: Flow<TransitionStep> =
repository.transition(DOZING, LOCKSCREEN)
+ /** Receive all [TransitionStep] matching a filter of [from]->[to] */
+ fun transition(from: KeyguardState, to: KeyguardState): Flow<TransitionStep> {
+ return repository.transition(from, to)
+ }
+
/**
* AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <->
* Lockscreen (0f).
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt
new file mode 100644
index 0000000..023d16ca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 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 com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor.Companion.TO_GONE_DURATION
+import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
+import com.android.systemui.keyguard.shared.model.ScrimAlpha
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Breaks down ALTERNATE_BOUNCER->GONE transition into discrete steps for corresponding views to
+ * consume.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class AlternateBouncerToGoneTransitionViewModel
+@Inject
+constructor(
+ bouncerToGoneFlows: BouncerToGoneFlows,
+) {
+
+ /** Scrim alpha values */
+ val scrimAlpha: Flow<ScrimAlpha> =
+ bouncerToGoneFlows.scrimAlpha(TO_GONE_DURATION, ALTERNATE_BOUNCER)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
new file mode 100644
index 0000000..da74f2f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2023 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 com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.ScrimAlpha
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import dagger.Lazy
+import javax.inject.Inject
+import kotlin.time.Duration
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.map
+
+/** ALTERNATE and PRIMARY bouncers common animations */
+@OptIn(ExperimentalCoroutinesApi::class)
+class BouncerToGoneFlows
+@Inject
+constructor(
+ private val interactor: KeyguardTransitionInteractor,
+ private val statusBarStateController: SysuiStatusBarStateController,
+ private val primaryBouncerInteractor: PrimaryBouncerInteractor,
+ private val keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>,
+ private val featureFlags: FeatureFlagsClassic,
+ private val shadeInteractor: ShadeInteractor,
+) {
+ /** Common fade for scrim alpha values during *BOUNCER->GONE */
+ fun scrimAlpha(duration: Duration, fromState: KeyguardState): Flow<ScrimAlpha> {
+ return if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ keyguardDismissActionInteractor
+ .get()
+ .willAnimateDismissActionOnLockscreen
+ .flatMapLatest { createScrimAlphaFlow(duration, fromState) { it } }
+ } else {
+ createScrimAlphaFlow(
+ duration,
+ fromState,
+ primaryBouncerInteractor::willRunDismissFromKeyguard
+ )
+ }
+ }
+
+ private fun createScrimAlphaFlow(
+ duration: Duration,
+ fromState: KeyguardState,
+ willRunAnimationOnKeyguard: () -> Boolean
+ ): Flow<ScrimAlpha> {
+ var isShadeExpanded = false
+ var leaveShadeOpen: Boolean = false
+ var willRunDismissFromKeyguard: Boolean = false
+ val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = duration,
+ transitionFlow = interactor.transition(fromState, GONE)
+ )
+
+ return shadeInteractor.shadeExpansion.flatMapLatest { shadeExpansion ->
+ transitionAnimation
+ .createFlow(
+ duration = duration,
+ interpolator = EMPHASIZED_ACCELERATE,
+ onStart = {
+ leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
+ willRunDismissFromKeyguard = willRunAnimationOnKeyguard()
+ isShadeExpanded = shadeExpansion > 0f
+ },
+ onStep = { 1f - it },
+ )
+ .map {
+ if (willRunDismissFromKeyguard) {
+ if (isShadeExpanded) {
+ ScrimAlpha(
+ behindAlpha = it,
+ notificationsAlpha = it,
+ )
+ } else {
+ ScrimAlpha()
+ }
+ } else if (leaveShadeOpen) {
+ ScrimAlpha(
+ behindAlpha = 1f,
+ notificationsAlpha = 1f,
+ )
+ } else {
+ ScrimAlpha(behindAlpha = it)
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index 0783181..0e95be2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -16,7 +16,6 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlagsClassic
@@ -24,6 +23,8 @@
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -33,7 +34,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.map
/**
* Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to
@@ -49,11 +49,12 @@
private val primaryBouncerInteractor: PrimaryBouncerInteractor,
keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>,
featureFlags: FeatureFlagsClassic,
+ bouncerToGoneFlows: BouncerToGoneFlows,
) {
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
transitionDuration = TO_GONE_DURATION,
- transitionFlow = interactor.primaryBouncerToGoneTransition,
+ transitionFlow = interactor.transition(PRIMARY_BOUNCER, GONE)
)
private var leaveShadeOpen: Boolean = false
@@ -110,38 +111,6 @@
)
}
- /** Scrim alpha values */
val scrimAlpha: Flow<ScrimAlpha> =
- if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
- keyguardDismissActionInteractor
- .get()
- .willAnimateDismissActionOnLockscreen
- .flatMapLatest { createScrimAlphaFlow { it } }
- } else {
- createScrimAlphaFlow(primaryBouncerInteractor::willRunDismissFromKeyguard)
- }
- private fun createScrimAlphaFlow(willRunAnimationOnKeyguard: () -> Boolean): Flow<ScrimAlpha> {
- return transitionAnimation
- .createFlow(
- duration = TO_GONE_DURATION,
- interpolator = EMPHASIZED_ACCELERATE,
- onStart = {
- leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
- willRunDismissFromKeyguard = willRunAnimationOnKeyguard()
- },
- onStep = { 1f - it },
- )
- .map {
- if (willRunDismissFromKeyguard) {
- ScrimAlpha()
- } else if (leaveShadeOpen) {
- ScrimAlpha(
- behindAlpha = 1f,
- notificationsAlpha = 1f,
- )
- } else {
- ScrimAlpha(behindAlpha = it)
- }
- }
- }
+ bouncerToGoneFlows.scrimAlpha(TO_GONE_DURATION, PRIMARY_BOUNCER)
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt
index ce8b79c..d8cab6a 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt
@@ -23,7 +23,6 @@
import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_CAST as METRICS_CREATION_SOURCE_CAST
import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_SYSTEM_UI_SCREEN_RECORDER as METRICS_CREATION_SOURCE_SYSTEM_UI_SCREEN_RECORDER
import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN as METRICS_CREATION_SOURCE_UNKNOWN
-import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED
import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED as METRICS_STATE_PERMISSION_REQUEST_DISPLAYED
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
@@ -36,16 +35,22 @@
class MediaProjectionMetricsLogger
@Inject
constructor(private val service: IMediaProjectionManager) {
+
/**
* Request to log that the permission was requested.
*
+ * @param hostUid The UID of the package that initiates MediaProjection.
* @param sessionCreationSource The entry point requesting permission to capture.
*/
- fun notifyProjectionInitiated(sessionCreationSource: SessionCreationSource) {
- notifyToServer(
- MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED,
- sessionCreationSource
- )
+ fun notifyProjectionInitiated(hostUid: Int, sessionCreationSource: SessionCreationSource) {
+ try {
+ service.notifyPermissionRequestInitiated(
+ hostUid,
+ sessionCreationSource.toMetricsConstant()
+ )
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Error notifying server of projection initiated", e)
+ }
}
fun notifyPermissionRequestDisplayed() {
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 2d830d3..922f7e0 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -140,7 +140,7 @@
if (MediaProjectionServiceHelper.hasProjectionPermission(mUid, mPackageName)) {
if (savedInstanceState == null) {
mMediaProjectionMetricsLogger.notifyProjectionInitiated(
- SessionCreationSource.APP);
+ mUid, SessionCreationSource.APP);
}
final IMediaProjection projection =
MediaProjectionServiceHelper.createOrReuseProjection(mUid, mPackageName,
@@ -242,6 +242,7 @@
if (savedInstanceState == null) {
mMediaProjectionMetricsLogger.notifyProjectionInitiated(
+ mUid,
appName == null
? SessionCreationSource.CAST
: SessionCreationSource.APP);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index f469c6b..f602da4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -155,6 +155,7 @@
}
mMediaProjectionMetricsLogger.notifyProjectionInitiated(
+ mUserContextProvider.getUserContext().getUserId(),
SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);
return flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
index 1ecb127..ead10d6 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -16,6 +16,7 @@
package com.android.systemui.settings.brightness;
+import static android.content.Intent.EXTRA_BRIGHTNESS_DIALOG_IS_FULL_WIDTH;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManagerPolicyConstants.EXTRA_FROM_BRIGHTNESS_KEY;
@@ -83,7 +84,7 @@
private void setWindowAttributes() {
final Window window = getWindow();
- window.setGravity(Gravity.TOP | Gravity.LEFT);
+ window.setGravity(Gravity.TOP | Gravity.START);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.requestFeature(Window.FEATURE_NO_TITLE);
@@ -130,13 +131,14 @@
Configuration configuration = getResources().getConfiguration();
int orientation = configuration.orientation;
+ int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
- lp.width = getWindowManager().getDefaultDisplay().getWidth() / 2
- - lp.leftMargin * 2;
+ boolean shouldBeFullWidth = getIntent()
+ .getBooleanExtra(EXTRA_BRIGHTNESS_DIALOG_IS_FULL_WIDTH, false);
+ lp.width = (shouldBeFullWidth ? screenWidth : screenWidth / 2) - horizontalMargin * 2;
} else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
- lp.width = getWindowManager().getDefaultDisplay().getWidth()
- - lp.leftMargin * 2;
+ lp.width = screenWidth - horizontalMargin * 2;
}
frame.setLayoutParams(lp);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BackDropView.java b/packages/SystemUI/src/com/android/systemui/statusbar/BackDropView.java
deleted file mode 100644
index f1eb9fe..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BackDropView.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2014 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;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-/**
- * A view who contains media artwork.
- */
-public class BackDropView extends FrameLayout
-{
- private Runnable mOnVisibilityChangedRunnable;
-
- public BackDropView(Context context) {
- super(context);
- }
-
- public BackDropView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public BackDropView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public BackDropView(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-
- @Override
- protected void onVisibilityChanged(View changedView, int visibility) {
- super.onVisibilityChanged(changedView, visibility);
- if (changedView == this && mOnVisibilityChangedRunnable != null) {
- mOnVisibilityChangedRunnable.run();
- }
- }
-
- public void setOnVisibilityChangedRunnable(Runnable runnable) {
- mOnVisibilityChangedRunnable = runnable;
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index f32f1c2..710e59d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -21,6 +21,7 @@
import static android.os.UserHandle.USER_NULL;
import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS;
import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS;
+import static android.os.Flags.allowPrivateProfile;
import static com.android.systemui.DejankUtils.whitelistIpcs;
@@ -79,6 +80,7 @@
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executor;
+import java.util.Objects;
import javax.inject.Inject;
@@ -177,57 +179,50 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- switch (action) {
- case Intent.ACTION_USER_REMOVED:
- int removedUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (removedUserId != -1) {
- for (UserChangedListener listener : mListeners) {
- listener.onUserRemoved(removedUserId);
- }
+ if (Objects.equals(action, Intent.ACTION_USER_REMOVED)) {
+ int removedUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (removedUserId != -1) {
+ for (UserChangedListener listener : mListeners) {
+ listener.onUserRemoved(removedUserId);
}
- updateCurrentProfilesCache();
- break;
- case Intent.ACTION_USER_ADDED:
- updateCurrentProfilesCache();
- if (mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD)) {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
- mBackgroundHandler.post(() -> {
- initValuesForUser(userId);
- });
+ }
+ updateCurrentProfilesCache();
+ } else if (Objects.equals(action, Intent.ACTION_USER_ADDED)){
+ updateCurrentProfilesCache();
+ if (mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD)) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
+ mBackgroundHandler.post(() -> {
+ initValuesForUser(userId);
+ });
+ }
+ } else if (profileAvailabilityActions(action)) {
+ updateCurrentProfilesCache();
+ } else if (Objects.equals(action, Intent.ACTION_USER_UNLOCKED)) {
+ // Start the overview connection to the launcher service
+ // Connect if user hasn't connected yet
+ if (mOverviewProxyServiceLazy.get().getProxy() == null) {
+ mOverviewProxyServiceLazy.get().startConnectionToCurrentUser();
+ }
+ } else if (Objects.equals(action, NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION)) {
+ final IntentSender intentSender = intent.getParcelableExtra(
+ Intent.EXTRA_INTENT);
+ final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
+ if (intentSender != null) {
+ try {
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ mContext.startIntentSender(intentSender, null, 0, 0, 0,
+ options.toBundle());
+ } catch (IntentSender.SendIntentException e) {
+ /* ignore */
}
- break;
- case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
- case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
- updateCurrentProfilesCache();
- break;
- case Intent.ACTION_USER_UNLOCKED:
- // Start the overview connection to the launcher service
- // Connect if user hasn't connected yet
- if (mOverviewProxyServiceLazy.get().getProxy() == null) {
- mOverviewProxyServiceLazy.get().startConnectionToCurrentUser();
- }
- break;
- case NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION:
- final IntentSender intentSender = intent.getParcelableExtra(
- Intent.EXTRA_INTENT);
- final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
- if (intentSender != null) {
- try {
- ActivityOptions options = ActivityOptions.makeBasic();
- options.setPendingIntentBackgroundActivityStartMode(
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
- mContext.startIntentSender(intentSender, null, 0, 0, 0,
- options.toBundle());
- } catch (IntentSender.SendIntentException e) {
- /* ignore */
- }
- }
- if (notificationKey != null) {
- final NotificationVisibility nv = mVisibilityProviderLazy.get()
- .obtain(notificationKey, true);
- mClickNotifier.onNotificationClick(notificationKey, nv);
- }
- break;
+ }
+ if (notificationKey != null) {
+ final NotificationVisibility nv = mVisibilityProviderLazy.get()
+ .obtain(notificationKey, true);
+ mClickNotifier.onNotificationClick(notificationKey, nv);
+ }
}
}
};
@@ -403,6 +398,10 @@
filter.addAction(Intent.ACTION_USER_UNLOCKED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ if (allowPrivateProfile()){
+ filter.addAction(Intent.ACTION_PROFILE_AVAILABLE);
+ filter.addAction(Intent.ACTION_PROFILE_UNAVAILABLE);
+ }
mBroadcastDispatcher.registerReceiver(mBaseBroadcastReceiver, filter,
null /* executor */, UserHandle.ALL);
@@ -814,6 +813,14 @@
}
}
+ private boolean profileAvailabilityActions(String action){
+ return allowPrivateProfile()?
+ Objects.equals(action,Intent.ACTION_PROFILE_AVAILABLE)||
+ Objects.equals(action,Intent.ACTION_PROFILE_UNAVAILABLE):
+ Objects.equals(action,Intent.ACTION_MANAGED_PROFILE_AVAILABLE)||
+ Objects.equals(action,Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ }
+
@Override
public void dump(PrintWriter pw, String[] args) {
pw.println("NotificationLockscreenUserManager state:");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 389486f..9c4625e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -18,31 +18,21 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
-import android.app.WallpaperManager;
import android.content.Context;
-import android.graphics.Point;
import android.graphics.drawable.Icon;
-import android.hardware.display.DisplayManager;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
-import android.os.Trace;
import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.util.Log;
-import android.view.Display;
-import android.view.View;
-import android.widget.ImageView;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.controls.models.player.MediaData;
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData;
import com.android.systemui.media.controls.pipeline.MediaDataManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.dagger.CentralSurfacesModule;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -50,21 +40,13 @@
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
-import com.android.systemui.statusbar.phone.BiometricUnlockController;
-import com.android.systemui.statusbar.phone.LockscreenWallpaper;
-import com.android.systemui.statusbar.phone.ScrimController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
-import java.util.Comparator;
import java.util.HashSet;
-import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.stream.Collectors;
/**
* Handles tasks and state related to media notifications. For example, there is a 'current' media
@@ -74,9 +56,6 @@
private static final String TAG = "NotificationMediaManager";
public static final boolean DEBUG_MEDIA = false;
- private final StatusBarStateController mStatusBarStateController;
- private final SysuiColorExtractor mColorExtractor;
- private final KeyguardStateController mKeyguardStateController;
private static final HashSet<Integer> PAUSED_MEDIA_STATES = new HashSet<>();
private static final HashSet<Integer> CONNECTING_MEDIA_STATES = new HashSet<>();
static {
@@ -93,15 +72,6 @@
private final NotifPipeline mNotifPipeline;
private final NotifCollection mNotifCollection;
- @Nullable
- private BiometricUnlockController mBiometricUnlockController;
- @Nullable
- private ScrimController mScrimController;
- @Nullable
- private LockscreenWallpaper mLockscreenWallpaper;
- @VisibleForTesting
- boolean mIsLockscreenLiveWallpaperEnabled;
-
private final Context mContext;
private final ArrayList<MediaListener> mMediaListeners;
@@ -110,16 +80,6 @@
private String mMediaNotificationKey;
private MediaMetadata mMediaMetadata;
- private BackDropView mBackdrop;
- private ImageView mBackdropFront;
- private ImageView mBackdropBack;
- private final Point mTmpDisplaySize = new Point();
-
- private final DisplayManager mDisplayManager;
- @Nullable
- private List<String> mSmallerInternalDisplayUids;
- private Display mCurrentDisplay;
-
private final MediaController.Callback mMediaListener = new MediaController.Callback() {
@Override
public void onPlaybackStateChanged(PlaybackState state) {
@@ -142,7 +102,7 @@
Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
}
mMediaMetadata = metadata;
- dispatchUpdateMediaMetaData(true /* changed */, true /* allowAnimation */);
+ dispatchUpdateMediaMetaData();
}
};
@@ -155,23 +115,13 @@
NotifPipeline notifPipeline,
NotifCollection notifCollection,
MediaDataManager mediaDataManager,
- StatusBarStateController statusBarStateController,
- SysuiColorExtractor colorExtractor,
- KeyguardStateController keyguardStateController,
- DumpManager dumpManager,
- WallpaperManager wallpaperManager,
- DisplayManager displayManager) {
+ DumpManager dumpManager) {
mContext = context;
mMediaListeners = new ArrayList<>();
mVisibilityProvider = visibilityProvider;
mMediaDataManager = mediaDataManager;
mNotifPipeline = notifPipeline;
mNotifCollection = notifCollection;
- mStatusBarStateController = statusBarStateController;
- mColorExtractor = colorExtractor;
- mKeyguardStateController = keyguardStateController;
- mDisplayManager = displayManager;
- mIsLockscreenLiveWallpaperEnabled = wallpaperManager.isLockscreenLiveWallpaperEnabled();
setupNotifPipeline();
@@ -275,7 +225,7 @@
public void onNotificationRemoved(String key) {
if (key.equals(mMediaNotificationKey)) {
clearCurrentMediaNotification();
- dispatchUpdateMediaMetaData(true /* changed */, true /* allowEnterAnimation */);
+ dispatchUpdateMediaMetaData();
}
}
@@ -309,21 +259,18 @@
}
public void findAndUpdateMediaNotifications() {
- boolean metaDataChanged;
// TODO(b/169655907): get the semi-filtered notifications for current user
Collection<NotificationEntry> allNotifications = mNotifPipeline.getAllNotifs();
- metaDataChanged = findPlayingMediaNotification(allNotifications);
- dispatchUpdateMediaMetaData(metaDataChanged, true /* allowEnterAnimation */);
+ findPlayingMediaNotification(allNotifications);
+ dispatchUpdateMediaMetaData();
}
/**
* Find a notification and media controller associated with the playing media session, and
* update this manager's internal state.
- * @return whether the current MediaMetadata changed (and needs to be announced to listeners).
+ * TODO(b/273443374) check this method
*/
- boolean findPlayingMediaNotification(
- @NonNull Collection<NotificationEntry> allNotifications) {
- boolean metaDataChanged = false;
+ void findPlayingMediaNotification(@NonNull Collection<NotificationEntry> allNotifications) {
// Promote the media notification with a controller in 'playing' state, if any.
NotificationEntry mediaNotification = null;
MediaController controller = null;
@@ -359,8 +306,6 @@
Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: "
+ mMediaController + ", receive metadata: " + mMediaMetadata);
}
-
- metaDataChanged = true;
}
if (mediaNotification != null
@@ -371,8 +316,6 @@
+ mMediaNotificationKey);
}
}
-
- return metaDataChanged;
}
public void clearCurrentMediaNotification() {
@@ -380,10 +323,7 @@
clearCurrentMediaNotificationSession();
}
- private void dispatchUpdateMediaMetaData(boolean changed, boolean allowEnterAnimation) {
- if (mPresenter != null) {
- mPresenter.updateMediaMetaData(changed, allowEnterAnimation);
- }
+ private void dispatchUpdateMediaMetaData() {
@PlaybackState.State int state = getMediaControllerPlaybackState(mMediaController);
ArrayList<MediaListener> callbacks = new ArrayList<>(mMediaListeners);
for (int i = 0; i < callbacks.size(); i++) {
@@ -446,125 +386,6 @@
mMediaController = null;
}
- /**
- * Notify lockscreen wallpaper drawable the current internal display.
- */
- public void onDisplayUpdated(Display display) {
- Trace.beginSection("NotificationMediaManager#onDisplayUpdated");
- mCurrentDisplay = display;
- Trace.endSection();
- }
-
- private boolean isOnSmallerInternalDisplays() {
- if (mSmallerInternalDisplayUids == null) {
- mSmallerInternalDisplayUids = findSmallerInternalDisplayUids();
- }
- return mSmallerInternalDisplayUids.contains(mCurrentDisplay.getUniqueId());
- }
-
- private List<String> findSmallerInternalDisplayUids() {
- if (mSmallerInternalDisplayUids != null) {
- return mSmallerInternalDisplayUids;
- }
- List<Display> internalDisplays = Arrays.stream(mDisplayManager.getDisplays(
- DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED))
- .filter(display -> display.getType() == Display.TYPE_INTERNAL)
- .collect(Collectors.toList());
- if (internalDisplays.isEmpty()) {
- return List.of();
- }
- Display largestDisplay = internalDisplays.stream()
- .max(Comparator.comparingInt(this::getRealDisplayArea))
- .orElse(internalDisplays.get(0));
- internalDisplays.remove(largestDisplay);
- return internalDisplays.stream().map(Display::getUniqueId).collect(Collectors.toList());
- }
-
- private int getRealDisplayArea(Display display) {
- display.getRealSize(mTmpDisplaySize);
- return mTmpDisplaySize.x * mTmpDisplaySize.y;
- }
-
- /**
- * Update media state of lockscreen media views and controllers .
- */
- public void updateMediaMetaData(boolean metaDataChanged) {
-
- if (mIsLockscreenLiveWallpaperEnabled) return;
-
- Trace.beginSection("CentralSurfaces#updateMediaMetaData");
- if (getBackDropView() == null) {
- Trace.endSection();
- return; // called too early
- }
-
- boolean wakeAndUnlock = mBiometricUnlockController != null
- && mBiometricUnlockController.isWakeAndUnlock();
- if (mKeyguardStateController.isLaunchTransitionFadingAway() || wakeAndUnlock) {
- mBackdrop.setVisibility(View.INVISIBLE);
- Trace.endSection();
- return;
- }
-
- MediaMetadata mediaMetadata = getMediaMetadata();
-
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: updating album art for notification "
- + getMediaNotificationKey()
- + " metadata=" + mediaMetadata
- + " metaDataChanged=" + metaDataChanged
- + " state=" + mStatusBarStateController.getState());
- }
-
- mColorExtractor.setHasMediaArtwork(false);
- if (mScrimController != null) {
- mScrimController.setHasBackdrop(false);
- }
-
- Trace.endSection();
- }
-
- public void setup(BackDropView backdrop, ImageView backdropFront, ImageView backdropBack,
- ScrimController scrimController, LockscreenWallpaper lockscreenWallpaper) {
- mBackdrop = backdrop;
- mBackdropFront = backdropFront;
- mBackdropBack = backdropBack;
- mScrimController = scrimController;
- mLockscreenWallpaper = lockscreenWallpaper;
- }
-
- public void setBiometricUnlockController(BiometricUnlockController biometricUnlockController) {
- mBiometricUnlockController = biometricUnlockController;
- }
-
- /**
- * Hide the album artwork that is fading out and release its bitmap.
- */
- protected final Runnable mHideBackdropFront = new Runnable() {
- @Override
- public void run() {
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: removing fade layer");
- }
- mBackdropFront.setVisibility(View.INVISIBLE);
- mBackdropFront.animate().cancel();
- mBackdropFront.setImageDrawable(null);
- }
- };
-
- // TODO(b/273443374): remove
- public boolean isLockscreenWallpaperOnNotificationShade() {
- return mBackdrop != null && mLockscreenWallpaper != null
- && !mLockscreenWallpaper.isLockscreenLiveWallpaperEnabled()
- && (mBackdropFront.isVisibleToUser() || mBackdropBack.isVisibleToUser());
- }
-
- // TODO(b/273443374) temporary test helper; remove
- @VisibleForTesting
- BackDropView getBackDropView() {
- return mBackdrop;
- }
-
public interface MediaListener {
/**
* Called whenever there's new metadata or playback state.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 5dcf6d1..f3b5ab6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -32,11 +32,6 @@
boolean isPresenterFullyCollapsed();
/**
- * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
- */
- void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation);
-
- /**
* Called when the current user changes.
* @param newUserId new user id
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 125c8efe..1fe6b83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -16,9 +16,7 @@
package com.android.systemui.statusbar.dagger;
-import android.app.WallpaperManager;
import android.content.Context;
-import android.hardware.display.DisplayManager;
import android.os.RemoteException;
import android.service.dreams.IDreamManager;
import android.util.Log;
@@ -29,7 +27,6 @@
import com.android.systemui.animation.AnimationFeatureFlags;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpHandler;
import com.android.systemui.dump.DumpManager;
@@ -121,24 +118,14 @@
NotifPipeline notifPipeline,
NotifCollection notifCollection,
MediaDataManager mediaDataManager,
- StatusBarStateController statusBarStateController,
- SysuiColorExtractor colorExtractor,
- KeyguardStateController keyguardStateController,
- DumpManager dumpManager,
- WallpaperManager wallpaperManager,
- DisplayManager displayManager) {
+ DumpManager dumpManager) {
return new NotificationMediaManager(
context,
visibilityProvider,
notifPipeline,
notifCollection,
mediaDataManager,
- statusBarStateController,
- colorExtractor,
- keyguardStateController,
- dumpManager,
- wallpaperManager,
- displayManager);
+ dumpManager);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
index bde298d..ea1d782 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
@@ -36,6 +36,11 @@
val showAnimation: Boolean
val viewCreator: ViewCreator
var contentDescription: String?
+ /**
+ * When true, an accessibility event with [contentDescription] is announced when the view
+ * becomes visible.
+ */
+ val shouldAnnounceAccessibilityEvent: Boolean
// Update this event with values from another event.
fun updateFromEvent(other: StatusEvent?) {
@@ -76,6 +81,7 @@
override var forceVisible = false
override val showAnimation = true
override var contentDescription: String? = ""
+ override val shouldAnnounceAccessibilityEvent: Boolean = false
override val viewCreator: ViewCreator = { context ->
BatteryStatusChip(context).apply {
@@ -95,6 +101,7 @@
override var forceVisible = false
override val showAnimation = true
override var contentDescription: String? = ""
+ override val shouldAnnounceAccessibilityEvent: Boolean = true
override val viewCreator: ViewCreator = { context ->
ConnectedDisplayChip(context)
@@ -110,6 +117,7 @@
override var contentDescription: String? = null
override val priority = 100
override var forceVisible = true
+ override val shouldAnnounceAccessibilityEvent: Boolean = false
var privacyItems: List<PrivacyItem> = listOf()
private var privacyChip: OngoingPrivacyChip? = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
index dccc23f..73c0bfe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
@@ -273,6 +273,11 @@
})
}
+ /** Announces [contentDescriptions] for accessibility. */
+ fun announceForAccessibility(contentDescriptions: String) {
+ currentAnimatedView?.view?.announceForAccessibility(contentDescriptions)
+ }
+
private fun updateDimens(contentArea: Rect) {
val lp = animationWindowView.layoutParams as FrameLayout.LayoutParams
lp.height = contentArea.height()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
index 7d866df..8ee1ade 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
@@ -100,9 +100,12 @@
}
private fun startConnectedDisplayCollection() {
+ val connectedDisplayEvent = ConnectedDisplayEvent().apply {
+ contentDescription = context.getString(R.string.connected_display_icon_desc)
+ }
connectedDisplayCollectionJob =
onDisplayConnectedFlow
- .onEach { scheduler.onStatusEvent(ConnectedDisplayEvent()) }
+ .onEach { scheduler.onStatusEvent(connectedDisplayEvent) }
.launchIn(appScope)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
index a3bc002..f0e60dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
@@ -254,11 +254,18 @@
currentlyRunningAnimationJob =
coroutineScope.launch {
runChipAppearAnimation()
+ announceForAccessibilityIfNeeded(event)
delay(APPEAR_ANIMATION_DURATION + DISPLAY_LENGTH)
runChipDisappearAnimation()
}
}
+ private fun announceForAccessibilityIfNeeded(event: StatusEvent) {
+ val description = event.contentDescription ?: return
+ if (!event.shouldAnnounceAccessibilityEvent) return
+ chipAnimationController.announceForAccessibility(description)
+ }
+
/**
* 1. Define a total budget for the chip animation (1500ms)
* 2. Send out callbacks to listeners so that they can generate animations locally
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 59f10ae..daa4f18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -511,7 +511,6 @@
case MODE_WAKE_AND_UNLOCK:
if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) {
Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
- mMediaManager.updateMediaMetaData(false /* metaDataChanged */);
} else if (mMode == MODE_WAKE_AND_UNLOCK){
Trace.beginSection("MODE_WAKE_AND_UNLOCK");
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 8d9fd12..7cd32f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -76,7 +76,6 @@
import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.Log;
-import android.util.MathUtils;
import android.view.Display;
import android.view.IRemoteAnimationRunner;
import android.view.IWindowManager;
@@ -176,7 +175,6 @@
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.statusbar.AutoHideUiElement;
-import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CircleReveal;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.GestureRecorder;
@@ -237,10 +235,10 @@
import com.android.wm.shell.startingsurface.SplashscreenContentDrawer;
import com.android.wm.shell.startingsurface.StartingSurface;
-import dagger.Lazy;
-
import dalvik.annotation.optimization.NeverCompile;
+import dagger.Lazy;
+
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
@@ -376,9 +374,6 @@
private boolean mBrightnessMirrorVisible;
private BiometricUnlockController mBiometricUnlockController;
private final LightBarController mLightBarController;
- private final Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy;
- @Nullable
- protected LockscreenWallpaper mLockscreenWallpaper;
private final AutoHideController mAutoHideController;
private final Point mCurrentDisplaySize = new Point();
@@ -658,7 +653,6 @@
NotificationExpansionRepository notificationExpansionRepository,
DozeParameters dozeParameters,
ScrimController scrimController,
- Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
AuthRippleController authRippleController,
DozeServiceHost dozeServiceHost,
@@ -770,7 +764,6 @@
mPowerManager = powerManager;
mDozeParameters = dozeParameters;
mScrimController = scrimController;
- mLockscreenWallpaperLazy = lockscreenWallpaperLazy;
mDozeScrimController = dozeScrimController;
mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
mAuthRippleController = authRippleController;
@@ -1198,10 +1191,6 @@
createNavigationBar(result);
- if (ENABLE_LOCKSCREEN_WALLPAPER && mWallpaperSupported) {
- mLockscreenWallpaper = mLockscreenWallpaperLazy.get();
- }
-
mAmbientIndicationContainer = getNotificationShadeWindowView().findViewById(
R.id.ambient_indication_container);
@@ -1268,24 +1257,6 @@
mNotificationShelfController,
mHeadsUpManager);
- BackDropView backdrop = getNotificationShadeWindowView().findViewById(R.id.backdrop);
- if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
- mMediaManager.setup(null, null, null, mScrimController, null);
- } else {
- mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),
- backdrop.findViewById(R.id.backdrop_back), mScrimController,
- mLockscreenWallpaper);
- }
- float maxWallpaperZoom = mContext.getResources().getFloat(
- com.android.internal.R.dimen.config_wallpaperMaxScale);
- mNotificationShadeDepthControllerLazy.get().addListener(depth -> {
- float scale = MathUtils.lerp(maxWallpaperZoom, 1f, depth);
- backdrop.setPivotX(backdrop.getWidth() / 2f);
- backdrop.setPivotY(backdrop.getHeight() / 2f);
- backdrop.setScaleX(scale);
- backdrop.setScaleY(scale);
- });
-
// Set up the quick settings tile panel
final View container = getNotificationShadeWindowView().findViewById(R.id.qs_frame);
if (container != null) {
@@ -1357,14 +1328,6 @@
// receive broadcasts
registerBroadcastReceiver();
- IntentFilter demoFilter = new IntentFilter();
- if (DEBUG_MEDIA_FAKE_ARTWORK) {
- demoFilter.addAction(ACTION_FAKE_ARTWORK);
- }
- mContext.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
- android.Manifest.permission.DUMP, null,
- Context.RECEIVER_EXPORTED_UNAUDITED);
-
// listen for USER_SETUP_COMPLETE setting (per-user)
mDeviceProvisionedController.addCallback(mUserSetupObserver);
mUserSetupObserver.onUserSetupChanged();
@@ -1583,7 +1546,6 @@
mRemoteInputManager.addControllerCallback(mStatusBarKeyguardViewManager);
mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
- mMediaManager.setBiometricUnlockController(mBiometricUnlockController);
Trace.endSection();
}
@@ -1870,7 +1832,6 @@
void updateDisplaySize() {
mDisplay.getMetrics(mDisplayMetrics);
mDisplay.getSize(mCurrentDisplaySize);
- mMediaManager.onDisplayUpdated(mDisplay);
if (DEBUG_GESTURES) {
mGestureRec.tag("display",
String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
@@ -1944,19 +1905,6 @@
}
};
- private final BroadcastReceiver mDemoReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) Log.v(TAG, "onReceive: " + intent);
- String action = intent.getAction();
- if (ACTION_FAKE_ARTWORK.equals(action)) {
- if (DEBUG_MEDIA_FAKE_ARTWORK) {
- mPresenterLazy.get().updateMediaMetaData(true, true);
- }
- }
- }
- };
-
/**
* Reload some of our resources when the configuration changes.
*
@@ -2139,7 +2087,6 @@
releaseGestureWakeLock();
runLaunchTransitionEndRunnable();
mKeyguardStateController.setLaunchTransitionFadingAway(false);
- mPresenterLazy.get().updateMediaMetaData(true /* metaDataChanged */, true);
}
/**
@@ -2163,7 +2110,6 @@
beforeFading.run();
}
updateScrimController();
- mPresenterLazy.get().updateMediaMetaData(false, true);
mShadeSurface.resetAlpha();
mShadeSurface.fadeOut(
FADE_KEYGUARD_START_DELAY, FADE_KEYGUARD_DURATION,
@@ -3222,8 +3168,6 @@
updateDozingState();
checkBarModes();
updateScrimController();
- mPresenterLazy.get()
- .updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 2960520..2206be5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -546,8 +546,7 @@
* (1.0f - mKeyguardHeadsUpShowingAmount);
}
- if (mSystemEventAnimator.isAnimationRunning()
- && !mNotificationMediaManager.isLockscreenWallpaperOnNotificationShade()) {
+ if (mSystemEventAnimator.isAnimationRunning()) {
newAlpha = Math.min(newAlpha, mSystemEventAnimatorAlpha);
} else {
mView.setTranslationX(0);
@@ -704,21 +703,11 @@
private StatusBarSystemEventDefaultAnimator getSystemEventAnimator(boolean isAnimationRunning) {
return new StatusBarSystemEventDefaultAnimator(getResources(), (alpha) -> {
- // TODO(b/273443374): remove if-else condition
- if (!mNotificationMediaManager.isLockscreenWallpaperOnNotificationShade()) {
- mSystemEventAnimatorAlpha = alpha;
- } else {
- mSystemEventAnimatorAlpha = 1f;
- }
+ mSystemEventAnimatorAlpha = alpha;
updateViewState();
return Unit.INSTANCE;
}, (translationX) -> {
- // TODO(b/273443374): remove if-else condition
- if (!mNotificationMediaManager.isLockscreenWallpaperOnNotificationShade()) {
- mView.setTranslationX(translationX);
- } else {
- mView.setTranslationX(0);
- }
+ mView.setTranslationX(translationX);
return Unit.INSTANCE;
}, isAnimationRunning);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
deleted file mode 100644
index 00fd9fb..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (C) 2016 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.phone;
-
-import android.annotation.Nullable;
-import android.app.IWallpaperManager;
-import android.app.IWallpaperManagerCallback;
-import android.app.WallpaperColors;
-import android.app.WallpaperManager;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Rect;
-import android.graphics.Xfermode;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.DrawableWrapper;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.CoreStartable;
-import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.user.data.model.SelectedUserModel;
-import com.android.systemui.user.data.model.SelectionStatus;
-import com.android.systemui.user.data.repository.UserRepository;
-import com.android.systemui.util.kotlin.JavaAdapter;
-
-import libcore.io.IoUtils;
-
-import java.io.PrintWriter;
-import java.util.Objects;
-
-import javax.inject.Inject;
-
-/**
- * Manages the lockscreen wallpaper.
- */
-@SysUISingleton
-public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implements Runnable,
- Dumpable, CoreStartable {
-
- private static final String TAG = "LockscreenWallpaper";
-
- // TODO(b/253507223): temporary; remove this
- private static final String DISABLED_ERROR_MESSAGE = "Methods from LockscreenWallpaper.java "
- + "should not be called in this version. The lock screen wallpaper should be "
- + "managed by the WallpaperManagerService and not by this class.";
-
- private final NotificationMediaManager mMediaManager;
- private final WallpaperManager mWallpaperManager;
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final Handler mH;
- private final JavaAdapter mJavaAdapter;
- private final UserRepository mUserRepository;
-
- private boolean mCached;
- private Bitmap mCache;
- private int mCurrentUserId;
- // The user selected in the UI, or null if no user is selected or UI doesn't support selecting
- // users.
- private UserHandle mSelectedUser;
- private AsyncTask<Void, Void, LoaderResult> mLoader;
-
- @Inject
- public LockscreenWallpaper(WallpaperManager wallpaperManager,
- @Nullable IWallpaperManager iWallpaperManager,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- DumpManager dumpManager,
- NotificationMediaManager mediaManager,
- @Main Handler mainHandler,
- JavaAdapter javaAdapter,
- UserRepository userRepository,
- UserTracker userTracker) {
- dumpManager.registerDumpable(getClass().getSimpleName(), this);
- mWallpaperManager = wallpaperManager;
- mCurrentUserId = userTracker.getUserId();
- mUpdateMonitor = keyguardUpdateMonitor;
- mMediaManager = mediaManager;
- mH = mainHandler;
- mJavaAdapter = javaAdapter;
- mUserRepository = userRepository;
-
- if (iWallpaperManager != null && !mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
- // Service is disabled on some devices like Automotive
- try {
- iWallpaperManager.setLockWallpaperCallback(this);
- } catch (RemoteException e) {
- Log.e(TAG, "System dead?" + e);
- }
- }
- }
-
- @Override
- public void start() {
- if (!isLockscreenLiveWallpaperEnabled()) {
- mJavaAdapter.alwaysCollectFlow(
- mUserRepository.getSelectedUser(), this::setSelectedUser);
- }
- }
-
- public Bitmap getBitmap() {
- assertLockscreenLiveWallpaperNotEnabled();
-
- if (mCached) {
- return mCache;
- }
- if (!mWallpaperManager.isWallpaperSupported()) {
- mCached = true;
- mCache = null;
- return null;
- }
-
- LoaderResult result = loadBitmap(mCurrentUserId, mSelectedUser);
- if (result.success) {
- mCached = true;
- mCache = result.bitmap;
- }
- return mCache;
- }
-
- public LoaderResult loadBitmap(int currentUserId, UserHandle selectedUser) {
- // May be called on any thread - only use thread safe operations.
-
- assertLockscreenLiveWallpaperNotEnabled();
-
-
- if (!mWallpaperManager.isWallpaperSupported()) {
- // When wallpaper is not supported, show the system wallpaper
- return LoaderResult.success(null);
- }
-
- // Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
- // wallpaper.
- final int lockWallpaperUserId =
- selectedUser != null ? selectedUser.getIdentifier() : currentUserId;
- ParcelFileDescriptor fd = mWallpaperManager.getWallpaperFile(
- WallpaperManager.FLAG_LOCK, lockWallpaperUserId);
-
- if (fd != null) {
- try {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inPreferredConfig = Bitmap.Config.HARDWARE;
- return LoaderResult.success(BitmapFactory.decodeFileDescriptor(
- fd.getFileDescriptor(), null, options));
- } catch (OutOfMemoryError e) {
- Log.w(TAG, "Can't decode file", e);
- return LoaderResult.fail();
- } finally {
- IoUtils.closeQuietly(fd);
- }
- } else {
- if (selectedUser != null) {
- // Show the selected user's static wallpaper.
- return LoaderResult.success(mWallpaperManager.getBitmapAsUser(
- selectedUser.getIdentifier(), true /* hardware */));
-
- } else {
- // When there is no selected user, show the system wallpaper
- return LoaderResult.success(null);
- }
- }
- }
-
- private void setSelectedUser(SelectedUserModel selectedUserModel) {
- assertLockscreenLiveWallpaperNotEnabled();
-
- if (selectedUserModel.getSelectionStatus().equals(SelectionStatus.SELECTION_IN_PROGRESS)) {
- // Wait until the selection has finished before updating.
- return;
- }
-
- int user = selectedUserModel.getUserInfo().id;
- if (user != mCurrentUserId) {
- if (mSelectedUser == null || user != mSelectedUser.getIdentifier()) {
- mCached = false;
- }
- mCurrentUserId = user;
- }
- }
-
- public void setSelectedUser(UserHandle selectedUser) {
- assertLockscreenLiveWallpaperNotEnabled();
-
- if (Objects.equals(selectedUser, mSelectedUser)) {
- return;
- }
- mSelectedUser = selectedUser;
- postUpdateWallpaper();
- }
-
- @Override
- public void onWallpaperChanged() {
- assertLockscreenLiveWallpaperNotEnabled();
- // Called on Binder thread.
- postUpdateWallpaper();
- }
-
- @Override
- public void onWallpaperColorsChanged(WallpaperColors colors, int which, int userId) {
- assertLockscreenLiveWallpaperNotEnabled();
- }
-
- private void postUpdateWallpaper() {
- assertLockscreenLiveWallpaperNotEnabled();
- if (mH == null) {
- Log.wtfStack(TAG, "Trying to use LockscreenWallpaper before initialization.");
- return;
- }
- mH.removeCallbacks(this);
- mH.post(this);
- }
- @Override
- public void run() {
- // Called in response to onWallpaperChanged on the main thread.
-
- assertLockscreenLiveWallpaperNotEnabled();
-
- if (mLoader != null) {
- mLoader.cancel(false /* interrupt */);
- }
-
- final int currentUser = mCurrentUserId;
- final UserHandle selectedUser = mSelectedUser;
- mLoader = new AsyncTask<Void, Void, LoaderResult>() {
- @Override
- protected LoaderResult doInBackground(Void... params) {
- return loadBitmap(currentUser, selectedUser);
- }
-
- @Override
- protected void onPostExecute(LoaderResult result) {
- super.onPostExecute(result);
- if (isCancelled()) {
- return;
- }
- if (result.success) {
- mCached = true;
- mCache = result.bitmap;
- mMediaManager.updateMediaMetaData(true /* metaDataChanged */);
- }
- mLoader = null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- // TODO(b/273443374): remove
- public boolean isLockscreenLiveWallpaperEnabled() {
- return mWallpaperManager.isLockscreenLiveWallpaperEnabled();
- }
-
- @Override
- public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
- pw.println(getClass().getSimpleName() + ":");
- IndentingPrintWriter iPw = new IndentingPrintWriter(pw, " ").increaseIndent();
- iPw.println("mCached=" + mCached);
- iPw.println("mCache=" + mCache);
- iPw.println("mCurrentUserId=" + mCurrentUserId);
- iPw.println("mSelectedUser=" + mSelectedUser);
- }
-
- private static class LoaderResult {
- public final boolean success;
- public final Bitmap bitmap;
-
- LoaderResult(boolean success, Bitmap bitmap) {
- this.success = success;
- this.bitmap = bitmap;
- }
-
- static LoaderResult success(Bitmap b) {
- return new LoaderResult(true, b);
- }
-
- static LoaderResult fail() {
- return new LoaderResult(false, null);
- }
- }
-
- /**
- * Drawable that aligns left horizontally and center vertically (like ImageWallpaper).
- *
- * <p>Aligns to the center when showing on the smaller internal display of a multi display
- * device.
- */
- public static class WallpaperDrawable extends DrawableWrapper {
-
- private final ConstantState mState;
- private final Rect mTmpRect = new Rect();
- private boolean mIsOnSmallerInternalDisplays;
-
- public WallpaperDrawable(Resources r, Bitmap b, boolean isOnSmallerInternalDisplays) {
- this(r, new ConstantState(b), isOnSmallerInternalDisplays);
- }
-
- private WallpaperDrawable(Resources r, ConstantState state,
- boolean isOnSmallerInternalDisplays) {
- super(new BitmapDrawable(r, state.mBackground));
- mState = state;
- mIsOnSmallerInternalDisplays = isOnSmallerInternalDisplays;
- }
-
- @Override
- public void setXfermode(@Nullable Xfermode mode) {
- // DrawableWrapper does not call this for us.
- getDrawable().setXfermode(mode);
- }
-
- @Override
- public int getIntrinsicWidth() {
- return -1;
- }
-
- @Override
- public int getIntrinsicHeight() {
- return -1;
- }
-
- @Override
- protected void onBoundsChange(Rect bounds) {
- int vwidth = getBounds().width();
- int vheight = getBounds().height();
- int dwidth = mState.mBackground.getWidth();
- int dheight = mState.mBackground.getHeight();
- float scale;
- float dx = 0, dy = 0;
-
- if (dwidth * vheight > vwidth * dheight) {
- scale = (float) vheight / (float) dheight;
- } else {
- scale = (float) vwidth / (float) dwidth;
- }
-
- if (scale <= 1f) {
- scale = 1f;
- }
- dy = (vheight - dheight * scale) * 0.5f;
-
- int offsetX = 0;
- // Offset to show the center area of the wallpaper on a smaller display for multi
- // display device
- if (mIsOnSmallerInternalDisplays) {
- offsetX = bounds.centerX() - (Math.round(dwidth * scale) / 2);
- }
-
- mTmpRect.set(
- bounds.left + offsetX,
- bounds.top + Math.round(dy),
- bounds.left + Math.round(dwidth * scale) + offsetX,
- bounds.top + Math.round(dheight * scale + dy));
-
- super.onBoundsChange(mTmpRect);
- }
-
- @Override
- public ConstantState getConstantState() {
- return mState;
- }
-
- /**
- * Update bounds when the hosting display or the display size has changed.
- *
- * @param isOnSmallerInternalDisplays true if the drawable is on one of the internal
- * displays with the smaller area.
- */
- public void onDisplayUpdated(boolean isOnSmallerInternalDisplays) {
- mIsOnSmallerInternalDisplays = isOnSmallerInternalDisplays;
- onBoundsChange(getBounds());
- }
-
- static class ConstantState extends Drawable.ConstantState {
-
- private final Bitmap mBackground;
-
- ConstantState(Bitmap background) {
- mBackground = background;
- }
-
- @Override
- public Drawable newDrawable() {
- return newDrawable(null);
- }
-
- @Override
- public Drawable newDrawable(@Nullable Resources res) {
- return new WallpaperDrawable(res, this, /* isOnSmallerInternalDisplays= */ false);
- }
-
- @Override
- public int getChangingConfigurations() {
- // DrawableWrapper already handles this for us.
- return 0;
- }
- }
- }
-
- /**
- * Feature b/253507223 will adapt the logic to always use the
- * WallpaperManagerService to render the lock screen wallpaper.
- * Methods of this class should not be called at all if the project flag is enabled.
- * TODO(b/253507223) temporary assertion; remove this
- */
- private void assertLockscreenLiveWallpaperNotEnabled() {
- if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
- throw new IllegalStateException(DISABLED_ERROR_MESSAGE);
- }
- }
-}
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 54d81b8..5a8b636 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -300,7 +300,8 @@
mIconController.setIconVisibility(mSlotCast, false);
// connected display
- mIconController.setIcon(mSlotConnectedDisplay, R.drawable.stat_sys_connected_display, null);
+ mIconController.setIcon(mSlotConnectedDisplay, R.drawable.stat_sys_connected_display,
+ mResources.getString(R.string.connected_display_icon_desc));
mIconController.setIconVisibility(mSlotConnectedDisplay, false);
// hotspot
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 5b55264..744d70e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.GONE;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import static java.lang.Float.isNaN;
@@ -51,7 +54,6 @@
import com.android.systemui.CoreStartable;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
-import com.android.systemui.res.R;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.dagger.SysUISingleton;
@@ -62,7 +64,9 @@
import com.android.systemui.keyguard.shared.model.ScrimAlpha;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
+import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
+import com.android.systemui.res.R;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
@@ -273,6 +277,7 @@
private CoroutineDispatcher mMainDispatcher;
private boolean mIsBouncerToGoneTransitionRunning = false;
private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
+ private AlternateBouncerToGoneTransitionViewModel mAlternateBouncerToGoneTransitionViewModel;
private final Consumer<ScrimAlpha> mScrimAlphaConsumer =
(ScrimAlpha alphas) -> {
mInFrontAlpha = alphas.getFrontAlpha();
@@ -285,7 +290,7 @@
mScrimBehind.setViewAlpha(mBehindAlpha);
};
- Consumer<TransitionStep> mPrimaryBouncerToGoneTransition;
+ Consumer<TransitionStep> mBouncerToGoneTransition;
@Inject
public ScrimController(
@@ -304,6 +309,7 @@
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
+ AlternateBouncerToGoneTransitionViewModel alternateBouncerToGoneTransitionViewModel,
KeyguardTransitionInteractor keyguardTransitionInteractor,
WallpaperRepository wallpaperRepository,
@Main CoroutineDispatcher mainDispatcher,
@@ -349,6 +355,7 @@
});
mColors = new GradientColors();
mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel;
+ mAlternateBouncerToGoneTransitionViewModel = alternateBouncerToGoneTransitionViewModel;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mWallpaperRepository = wallpaperRepository;
mMainDispatcher = mainDispatcher;
@@ -405,7 +412,7 @@
// Directly control transition to UNLOCKED scrim state from PRIMARY_BOUNCER, and make sure
// to report back that keyguard has faded away. This fixes cases where the scrim state was
// rapidly switching on unlock, due to shifts in state in CentralSurfacesImpl
- mPrimaryBouncerToGoneTransition =
+ mBouncerToGoneTransition =
(TransitionStep step) -> {
TransitionState state = step.getTransitionState();
@@ -425,10 +432,17 @@
}
};
- collectFlow(behindScrim, mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition(),
- mPrimaryBouncerToGoneTransition, mMainDispatcher);
+ // PRIMARY_BOUNCER->GONE
+ collectFlow(behindScrim, mKeyguardTransitionInteractor.transition(PRIMARY_BOUNCER, GONE),
+ mBouncerToGoneTransition, mMainDispatcher);
collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha(),
mScrimAlphaConsumer, mMainDispatcher);
+
+ // ALTERNATE_BOUNCER->GONE
+ collectFlow(behindScrim, mKeyguardTransitionInteractor.transition(ALTERNATE_BOUNCER, GONE),
+ mBouncerToGoneTransition, mMainDispatcher);
+ collectFlow(behindScrim, mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha(),
+ mScrimAlphaConsumer, mMainDispatcher);
}
// TODO(b/270984686) recompute scrim height accurately, based on shade contents.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 90fddd9..267b563 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -964,9 +964,6 @@
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
}
- if (isShowing) {
- mMediaManager.updateMediaMetaData(false);
- }
mNotificationShadeWindowController.setKeyguardOccluded(isOccluded);
// setDozing(false) will call reset once we stop dozing. Also, if we're going away, there's
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 57a8e6f..a5cd062 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -205,7 +205,6 @@
// End old BaseStatusBar.userSwitched
mCommandQueue.animateCollapsePanels();
mMediaManager.clearCurrentMediaNotification();
- updateMediaMetaData(true, false);
}
@Override
@@ -220,11 +219,6 @@
}
@Override
- public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
- mMediaManager.updateMediaMetaData(metaDataChanged);
- }
-
- @Override
public void onExpandClicked(NotificationEntry clickedEntry, View clickedView,
boolean nowExpanded) {
mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialog.kt
index 85fd2af..d7f3b07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialog.kt
@@ -17,42 +17,71 @@
import android.app.Dialog
import android.content.Context
+import android.content.res.Configuration
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.Gravity
-import android.view.WindowManager
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import android.view.WindowManager.LayoutParams.MATCH_PARENT
+import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
+import android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS
+import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL
import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
/** A dialog shown as a bottom sheet. */
open class SystemUIBottomSheetDialog(
context: Context,
- theme: Int = R.style.Theme_SystemUI_Dialog,
+ private val configurationController: ConfigurationController? = null,
+ theme: Int = R.style.Theme_SystemUI_Dialog
) : Dialog(context, theme) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
-
- window?.apply {
- setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
- addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
-
- setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
- setGravity(Gravity.BOTTOM)
- val edgeToEdgeHorizontally =
- context.resources.getBoolean(R.bool.config_edgeToEdgeBottomSheetDialog)
- if (edgeToEdgeHorizontally) {
- decorView.setPadding(0, 0, 0, 0)
- setLayout(
- WindowManager.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.WRAP_CONTENT
- )
-
- val lp = attributes
- lp.fitInsetsSides = 0
- lp.horizontalMargin = 0f
- attributes = lp
- }
- }
+ setupWindow()
+ setupEdgeToEdge()
setCanceledOnTouchOutside(true)
}
+
+ private fun setupWindow() {
+ window?.apply {
+ setType(TYPE_STATUS_BAR_SUB_PANEL)
+ addPrivateFlags(SYSTEM_FLAG_SHOW_FOR_ALL_USERS or PRIVATE_FLAG_NO_MOVE_ANIMATION)
+ setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+ setGravity(Gravity.BOTTOM)
+ decorView.setPadding(0, 0, 0, 0)
+ attributes =
+ attributes.apply {
+ fitInsetsSides = 0
+ horizontalMargin = 0f
+ }
+ }
+ }
+
+ private fun setupEdgeToEdge() {
+ val edgeToEdgeHorizontally =
+ context.resources.getBoolean(R.bool.config_edgeToEdgeBottomSheetDialog)
+ val width = if (edgeToEdgeHorizontally) MATCH_PARENT else WRAP_CONTENT
+ val height = WRAP_CONTENT
+ window?.setLayout(width, height)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ configurationController?.addCallback(onConfigChanged)
+ }
+
+ override fun onStop() {
+ super.onStop()
+ configurationController?.removeCallback(onConfigChanged)
+ }
+
+ private val onConfigChanged =
+ object : ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ super.onConfigChanged(newConfig)
+ setupEdgeToEdge()
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 9d627af..2558645 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -45,6 +45,7 @@
import com.android.systemui.res.R;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.model.SysUiState;
@@ -54,8 +55,14 @@
import java.util.ArrayList;
import java.util.List;
+import javax.inject.Inject;
+
/**
- * Base class for dialogs that should appear over panels and keyguard.
+ * Class for dialogs that should appear over panels and keyguard.
+ *
+ * DO NOT SUBCLASS THIS. See {@link SystemUIDialog.Delegate} for an interface that enables
+ * customizing behavior via composition instead of inheritance. Clients should implement the
+ * Delegate class and then pass their implementation into the SystemUIDialog constructor.
*
* Optionally provide a {@link SystemUIDialogManager} to its constructor to send signals to
* listeners on whether this dialog is showing.
@@ -72,6 +79,7 @@
private final Context mContext;
private final FeatureFlags mFeatureFlags;
+ private final Delegate mDelegate;
@Nullable private final DismissReceiver mDismissReceiver;
private final Handler mHandler = new Handler();
private final SystemUIDialogManager mDialogManager;
@@ -101,18 +109,102 @@
Dependency.get(SystemUIDialogManager.class),
Dependency.get(SysUiState.class),
Dependency.get(BroadcastDispatcher.class),
- Dependency.get(DialogLaunchAnimator.class));
+ Dependency.get(DialogLaunchAnimator.class),
+ new Delegate() {});
}
- public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock,
+ @Inject
+ public SystemUIDialog(
+ @Application Context context,
+ FeatureFlags featureFlags,
+ SystemUIDialogManager systemUIDialogManager,
+ SysUiState sysUiState,
+ BroadcastDispatcher broadcastDispatcher,
+ DialogLaunchAnimator dialogLaunchAnimator) {
+ this(context,
+ DEFAULT_THEME,
+ DEFAULT_DISMISS_ON_DEVICE_LOCK,
+ featureFlags,
+ systemUIDialogManager,
+ sysUiState,
+ broadcastDispatcher,
+ dialogLaunchAnimator,
+ new Delegate(){});
+ }
+
+ public static class Factory {
+ private final Context mContext;
+ private final FeatureFlags mFeatureFlags;
+ private final SystemUIDialogManager mSystemUIDialogManager;
+ private final SysUiState mSysUiState;
+ private final BroadcastDispatcher mBroadcastDispatcher;
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
+
+ @Inject
+ public Factory(
+ @Application Context context,
+ FeatureFlags featureFlags,
+ SystemUIDialogManager systemUIDialogManager,
+ SysUiState sysUiState,
+ BroadcastDispatcher broadcastDispatcher,
+ DialogLaunchAnimator dialogLaunchAnimator) {
+ mContext = context;
+ mFeatureFlags = featureFlags;
+ mSystemUIDialogManager = systemUIDialogManager;
+ mSysUiState = sysUiState;
+ mBroadcastDispatcher = broadcastDispatcher;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
+ }
+
+ public SystemUIDialog create(Delegate delegate) {
+ return new SystemUIDialog(
+ mContext,
+ DEFAULT_THEME,
+ DEFAULT_DISMISS_ON_DEVICE_LOCK,
+ mFeatureFlags,
+ mSystemUIDialogManager,
+ mSysUiState,
+ mBroadcastDispatcher,
+ mDialogLaunchAnimator,
+ delegate);
+ }
+ }
+
+ public SystemUIDialog(
+ Context context,
+ int theme,
+ boolean dismissOnDeviceLock,
FeatureFlags featureFlags,
SystemUIDialogManager dialogManager,
SysUiState sysUiState,
BroadcastDispatcher broadcastDispatcher,
DialogLaunchAnimator dialogLaunchAnimator) {
+ this(
+ context,
+ theme,
+ dismissOnDeviceLock,
+ featureFlags,
+ dialogManager,
+ sysUiState,
+ broadcastDispatcher,
+ dialogLaunchAnimator,
+ new Delegate(){});
+ }
+
+ public SystemUIDialog(
+ Context context,
+ int theme,
+ boolean dismissOnDeviceLock,
+ FeatureFlags featureFlags,
+ SystemUIDialogManager dialogManager,
+ SysUiState sysUiState,
+ BroadcastDispatcher broadcastDispatcher,
+ DialogLaunchAnimator dialogLaunchAnimator,
+ Delegate delegate) {
super(context, theme);
mContext = context;
mFeatureFlags = featureFlags;
+ mDelegate = delegate;
applyFlags(this);
WindowManager.LayoutParams attrs = getWindow().getAttributes();
@@ -127,7 +219,9 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
+ mDelegate.beforeCreate(this, savedInstanceState);
super.onCreate(savedInstanceState);
+ mDelegate.onCreate(this, savedInstanceState);
Configuration config = getContext().getResources().getConfiguration();
mLastConfigurationWidthDp = config.screenWidthDp;
@@ -172,6 +266,8 @@
updateWindowSize();
}
+
+ mDelegate.onConfigurationChanged(this, configuration);
}
/**
@@ -212,7 +308,9 @@
* Called when {@link #onStart} is called. Subclasses wishing to override {@link #onStart()}
* should override this method instead.
*/
- protected void start() {}
+ protected void start() {
+ mDelegate.start(this);
+ }
@Override
protected final void onStop() {
@@ -234,7 +332,15 @@
* Called when {@link #onStop} is called. Subclasses wishing to override {@link #onStop()}
* should override this method instead.
*/
- protected void stop() {}
+ protected void stop() {
+ mDelegate.stop(this);
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ mDelegate.onWindowFocusChanged(this, hasFocus);
+ }
public void setShowForAllUsers(boolean show) {
setShowForAllUsers(this, show);
@@ -353,7 +459,6 @@
registerDismissListener(dialog, null);
}
-
/**
* Registers a listener that dismisses the given dialog when it receives
* the screen off / close system dialogs broadcast.
@@ -480,4 +585,42 @@
}
}
+ /**
+ * A delegate class that should be implemented in place of sublcassing {@link SystemUIDialog}.
+ *
+ * Implement this interface and then pass an instance of your implementation to
+ * {@link SystemUIDialog.Factory#create(Delegate)}.
+ */
+ public interface Delegate {
+ /**
+ * Called before {@link AlertDialog#onCreate} is called.
+ */
+ default void beforeCreate(SystemUIDialog dialog, Bundle savedInstanceState) {}
+
+ /**
+ * Called after {@link AlertDialog#onCreate} is called.
+ */
+ default void onCreate(SystemUIDialog dialog, Bundle savedInstanceState) {}
+
+ /**
+ * Called after {@link AlertDialog#onStart} is called.
+ */
+ default void start(SystemUIDialog dialog) {}
+
+ /**
+ * Called after {@link AlertDialog#onStop} is called.
+ */
+ default void stop(SystemUIDialog dialog) {}
+
+ /**
+ * Called after {@link AlertDialog#onWindowFocusChanged(boolean)} is called.
+ */
+ default void onWindowFocusChanged(SystemUIDialog dialog, boolean hasFocus) {}
+
+ /**
+ * Called as part of
+ * {@link ViewRootImpl.ConfigChangedCallback#onConfigurationChanged(Configuration)}.
+ */
+ default void onConfigurationChanged(SystemUIDialog dialog, Configuration configuration) {}
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt
index 9269df3..8c66c2f 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt
@@ -19,6 +19,7 @@
import android.content.ContentResolver
import android.content.Context
import android.hardware.devicestate.DeviceStateManager
+import android.os.Trace
import android.util.Log
import com.android.internal.util.LatencyTracker
import com.android.systemui.dagger.SysUISingleton
@@ -57,6 +58,7 @@
private var folded: Boolean? = null
private var isTransitionEnabled: Boolean? = null
private val foldStateListener = FoldStateListener(context)
+ private var unfoldInProgress = false
private val isFoldable: Boolean
get() =
context.resources
@@ -95,7 +97,7 @@
// the unfold animation (e.g. it could be disabled because of battery saver).
// When animation is enabled finishing of the tracking will be done in onTransitionStarted.
if (folded == false && isTransitionEnabled == false) {
- latencyTracker.onActionEnd(LatencyTracker.ACTION_SWITCH_DISPLAY_UNFOLD)
+ onUnfoldEnded()
if (DEBUG) {
Log.d(TAG, "onScreenTurnedOn: ending ACTION_SWITCH_DISPLAY_UNFOLD")
@@ -116,7 +118,7 @@
}
if (folded == false && isTransitionEnabled == true) {
- latencyTracker.onActionEnd(LatencyTracker.ACTION_SWITCH_DISPLAY_UNFOLD)
+ onUnfoldEnded()
if (DEBUG) {
Log.d(TAG, "onTransitionStarted: ending ACTION_SWITCH_DISPLAY_UNFOLD")
@@ -124,6 +126,22 @@
}
}
+ private fun onUnfoldStarted() {
+ if (unfoldInProgress) return
+ unfoldInProgress = true
+ // As LatencyTracker might be disabled, let's also log a parallel slice to the trace to be
+ // able to debug all cases.
+ latencyTracker.onActionStart(LatencyTracker.ACTION_SWITCH_DISPLAY_UNFOLD)
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_APP, UNFOLD_IN_PROGRESS_TRACE_NAME, /* cookie= */ 0)
+ }
+
+ private fun onUnfoldEnded() {
+ if (!unfoldInProgress) return
+ unfoldInProgress = false
+ latencyTracker.onActionEnd(LatencyTracker.ACTION_SWITCH_DISPLAY_UNFOLD)
+ Trace.endAsyncSection(UNFOLD_IN_PROGRESS_TRACE_NAME, 0)
+ }
+
private fun onFoldEvent(folded: Boolean) {
val oldFolded = this.folded
@@ -139,7 +157,7 @@
// unfolding the device.
if (oldFolded != null && !folded) {
// Unfolding started
- latencyTracker.onActionStart(LatencyTracker.ACTION_SWITCH_DISPLAY_UNFOLD)
+ onUnfoldStarted()
isTransitionEnabled =
transitionProgressProvider.isPresent && contentResolver.areAnimationsEnabled()
@@ -159,4 +177,5 @@
}
private const val TAG = "UnfoldLatencyTracker"
+private const val UNFOLD_IN_PROGRESS_TRACE_NAME = "Switch displays during unfold"
private val DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE)
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTraceLogger.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTraceLogger.kt
new file mode 100644
index 0000000..ed960f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTraceLogger.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 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.unfold
+
+import android.content.Context
+import android.os.Trace
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.unfold.system.DeviceStateRepository
+import com.android.systemui.unfold.updates.FoldStateRepository
+import com.android.systemui.util.TraceStateLogger
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Logs several unfold related details in a trace. Mainly used for debugging and investigate
+ * droidfooders traces.
+ */
+@SysUISingleton
+class UnfoldTraceLogger
+@Inject
+constructor(
+ private val context: Context,
+ private val foldStateRepository: FoldStateRepository,
+ @Application private val applicationScope: CoroutineScope,
+ private val deviceStateRepository: DeviceStateRepository
+) : CoreStartable {
+ private val isFoldable: Boolean
+ get() =
+ context.resources
+ .getIntArray(com.android.internal.R.array.config_foldedDeviceStates)
+ .isNotEmpty()
+
+ override fun start() {
+ if (!isFoldable) return
+
+ applicationScope.launch {
+ val foldUpdateLogger = TraceStateLogger("FoldUpdate")
+ foldStateRepository.foldUpdate.collect { foldUpdateLogger.log(it.name) }
+ }
+
+ applicationScope.launch {
+ foldStateRepository.hingeAngle.collect {
+ Trace.traceCounter(Trace.TRACE_TAG_APP, "hingeAngle", it.toInt())
+ }
+ }
+ applicationScope.launch {
+ val foldedStateLogger = TraceStateLogger("FoldedState")
+ deviceStateRepository.isFolded.collect { isFolded ->
+ foldedStateLogger.log(
+ if (isFolded) {
+ "folded"
+ } else {
+ "unfolded"
+ }
+ )
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
index ed3eacd..71314f1 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.hardware.devicestate.DeviceStateManager
import android.os.SystemProperties
+import com.android.systemui.CoreStartable
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.LifecycleScreenStatusProvider
@@ -34,16 +35,26 @@
import com.android.systemui.unfold.util.UnfoldTransitionATracePrefix
import com.android.systemui.util.time.SystemClockImpl
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider
+import dagger.Binds
import dagger.Lazy
import dagger.Module
import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
import java.util.Optional
import java.util.concurrent.Executor
import javax.inject.Named
import javax.inject.Provider
import javax.inject.Singleton
-@Module(includes = [UnfoldSharedModule::class, SystemUnfoldSharedModule::class])
+@Module(
+ includes =
+ [
+ UnfoldSharedModule::class,
+ SystemUnfoldSharedModule::class,
+ UnfoldTransitionModule.Bindings::class
+ ]
+)
class UnfoldTransitionModule {
@Provides @UnfoldTransitionATracePrefix fun tracingTagPrefix() = "systemui"
@@ -136,13 +147,22 @@
null
}
- return resultingProvider?.get()?.orElse(null)?.let {
- unfoldProgressProvider -> UnfoldProgressProvider(unfoldProgressProvider, foldProvider)
- } ?: ShellUnfoldProgressProvider.NO_PROVIDER
+ return resultingProvider?.get()?.orElse(null)?.let { unfoldProgressProvider ->
+ UnfoldProgressProvider(unfoldProgressProvider, foldProvider)
+ }
+ ?: ShellUnfoldProgressProvider.NO_PROVIDER
}
@Provides
fun screenStatusProvider(impl: LifecycleScreenStatusProvider): ScreenStatusProvider = impl
+
+ @Module
+ interface Bindings {
+ @Binds
+ @IntoMap
+ @ClassKey(UnfoldTraceLogger::class)
+ fun bindUnfoldTraceLogger(impl: UnfoldTraceLogger): CoreStartable
+ }
}
const val UNFOLD_STATUS_BAR = "unfold_status_bar"
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index aea3030..fdf59664 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -126,8 +126,6 @@
private int mBitmapUsages = 0;
private final Object mLock = new Object();
- private boolean mIsLockscreenLiveWallpaperEnabled;
-
CanvasEngine() {
super();
setFixedSizeAllowed(true);
@@ -171,12 +169,8 @@
Log.d(TAG, "onCreate");
}
mWallpaperManager = getDisplayContext().getSystemService(WallpaperManager.class);
- mIsLockscreenLiveWallpaperEnabled = mWallpaperManager
- .isLockscreenLiveWallpaperEnabled();
mSurfaceHolder = surfaceHolder;
- Rect dimensions = mIsLockscreenLiveWallpaperEnabled
- ? mWallpaperManager.peekBitmapDimensions(getSourceFlag(), true)
- : mWallpaperManager.peekBitmapDimensions();
+ Rect dimensions = mWallpaperManager.peekBitmapDimensions(getSourceFlag(), true);
int width = Math.max(MIN_SURFACE_WIDTH, dimensions.width());
int height = Math.max(MIN_SURFACE_HEIGHT, dimensions.height());
mSurfaceHolder.setFixedSize(width, height);
@@ -327,10 +321,8 @@
boolean loadSuccess = false;
Bitmap bitmap;
try {
- bitmap = mIsLockscreenLiveWallpaperEnabled
- ? mWallpaperManager.getBitmapAsUser(
- mUserTracker.getUserId(), false, getSourceFlag(), true)
- : mWallpaperManager.getBitmapAsUser(mUserTracker.getUserId(), false);
+ bitmap = mWallpaperManager.getBitmapAsUser(
+ mUserTracker.getUserId(), false, getSourceFlag(), true);
if (bitmap != null
&& bitmap.getByteCount() > RecordingCanvas.MAX_BITMAP_SIZE) {
throw new RuntimeException("Wallpaper is too large to draw!");
@@ -341,18 +333,11 @@
// be loaded, we will go into a cycle. Don't do a build where the
// default wallpaper can't be loaded.
Log.w(TAG, "Unable to load wallpaper!", exception);
- if (mIsLockscreenLiveWallpaperEnabled) {
- mWallpaperManager.clearWallpaper(getWallpaperFlags(), mUserTracker.getUserId());
- } else {
- mWallpaperManager.clearWallpaper(
- WallpaperManager.FLAG_SYSTEM, mUserTracker.getUserId());
- }
+ mWallpaperManager.clearWallpaper(getWallpaperFlags(), mUserTracker.getUserId());
try {
- bitmap = mIsLockscreenLiveWallpaperEnabled
- ? mWallpaperManager.getBitmapAsUser(
- mUserTracker.getUserId(), false, getSourceFlag(), true)
- : mWallpaperManager.getBitmapAsUser(mUserTracker.getUserId(), false);
+ bitmap = mWallpaperManager.getBitmapAsUser(
+ mUserTracker.getUserId(), false, getSourceFlag(), true);
} catch (RuntimeException | OutOfMemoryError e) {
Log.w(TAG, "Unable to load default wallpaper!", e);
bitmap = null;
@@ -373,9 +358,7 @@
mBitmap.recycle();
}
mBitmap = bitmap;
- mWideColorGamut = mIsLockscreenLiveWallpaperEnabled
- ? mWallpaperManager.wallpaperSupportsWcg(getSourceFlag())
- : mWallpaperManager.wallpaperSupportsWcg(WallpaperManager.FLAG_SYSTEM);
+ mWideColorGamut = mWallpaperManager.wallpaperSupportsWcg(getSourceFlag());
// +2 usages for the color extraction and the delayed unload.
mBitmapUsages += 2;
diff --git a/packages/SystemUI/tests/src/com/android/SysUITestModule.kt b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
index ea74510..0b3c3b4 100644
--- a/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
+++ b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
@@ -16,10 +16,12 @@
package com.android
import android.content.Context
+import android.content.res.Resources
import com.android.systemui.FakeSystemUiModule
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
import dagger.Module
import dagger.Provides
@@ -36,6 +38,9 @@
@Provides @Application fun provideAppContext(test: SysuiTestCase): Context = test.context
+ @Provides @Main
+ fun provideResources(@Application context: Context): Resources = context.resources
+
@Provides
fun provideBroadcastDispatcher(test: SysuiTestCase): BroadcastDispatcher =
test.fakeBroadcastDispatcher
diff --git a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
index 167e341..ff1d5b2 100644
--- a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
+++ b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
@@ -22,7 +22,9 @@
import com.android.internal.logging.MetricsLogger
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardViewController
import com.android.systemui.GuestResumeSessionReceiver
+import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.ScreenLifecycle
@@ -31,6 +33,7 @@
import com.android.systemui.log.dagger.BroadcastDispatcherLog
import com.android.systemui.log.dagger.SceneFrameworkLog
import com.android.systemui.media.controls.ui.MediaHierarchyManager
+import com.android.systemui.model.SysUiState
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -86,6 +89,9 @@
@get:Provides val statusBarStateController: SysuiStatusBarStateController = mock(),
@get:Provides val statusBarWindowController: StatusBarWindowController = mock(),
@get:Provides val wakefulnessLifecycle: WakefulnessLifecycle = mock(),
+ @get:Provides val keyguardViewController: KeyguardViewController = mock(),
+ @get:Provides val dialogLaunchAnimator: DialogLaunchAnimator = mock(),
+ @get:Provides val sysuiState: SysUiState = mock(),
// log buffers
@get:[Provides BroadcastDispatcherLog]
diff --git a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
index 80b281e..882bcab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
@@ -17,7 +17,6 @@
package com.android.systemui.colorextraction;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -105,21 +104,6 @@
}
@Test
- public void getColors_fallbackWhenMediaIsVisible() {
- simulateEvent(mColorExtractor);
- mColorExtractor.setHasMediaArtwork(true);
-
- ColorExtractor.GradientColors fallbackColors = mColorExtractor.getNeutralColors();
-
- for (int type : sTypes) {
- assertEquals("Not using fallback!",
- mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, type), fallbackColors);
- assertNotEquals("Media visibility should not affect system wallpaper.",
- mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, type), fallbackColors);
- }
- }
-
- @Test
public void onUiModeChanged_reloadsColors() {
Tonal tonal = mock(Tonal.class);
ConfigurationController configurationController = mock(ConfigurationController.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
index 7a13a0a..489665c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
@@ -106,7 +106,6 @@
whenever(keyguardViewController.viewRootImpl).thenReturn(mock(ViewRootImpl::class.java))
whenever(powerManager.isInteractive).thenReturn(true)
- whenever(wallpaperManager.isLockscreenLiveWallpaperEnabled).thenReturn(false)
// All of these fields are final, so we can't mock them, but are needed so that the surface
// appear amount setter doesn't short circuit.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
new file mode 100644
index 0000000..1ff46db
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2023 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.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
+import com.android.systemui.keyguard.shared.model.ScrimAlpha
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.util.mockito.whenever
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BouncerToGoneFlowsTest : SysuiTestCase() {
+ private lateinit var underTest: BouncerToGoneFlows
+ private lateinit var repository: FakeKeyguardTransitionRepository
+ private lateinit var featureFlags: FakeFeatureFlags
+ @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+ @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ @Mock
+ private lateinit var keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>
+ @Mock private lateinit var shadeInteractor: ShadeInteractor
+
+ private val shadeExpansionStateFlow = MutableStateFlow(0.1f)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(shadeInteractor.shadeExpansion).thenReturn(shadeExpansionStateFlow)
+
+ repository = FakeKeyguardTransitionRepository()
+ val featureFlags =
+ FakeFeatureFlags().apply { set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) }
+ val interactor =
+ KeyguardTransitionInteractorFactory.create(
+ scope = TestScope().backgroundScope,
+ repository = repository,
+ )
+ .keyguardTransitionInteractor
+ underTest =
+ BouncerToGoneFlows(
+ interactor,
+ statusBarStateController,
+ primaryBouncerInteractor,
+ keyguardDismissActionInteractor,
+ featureFlags,
+ shadeInteractor,
+ )
+
+ whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false)
+ whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false)
+ }
+
+ @Test
+ fun scrimAlpha_runDimissFromKeyguard_shadeExpanded() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
+ shadeExpansionStateFlow.value = 1f
+ whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(4)
+ values.forEach { assertThat(it.frontAlpha).isEqualTo(0f) }
+ values.forEach { assertThat(it.behindAlpha).isIn(Range.closed(0f, 1f)) }
+ values.forEach { assertThat(it.notificationsAlpha).isIn(Range.closed(0f, 1f)) }
+ }
+
+ @Test
+ fun scrimAlpha_runDimissFromKeyguard_shadeNotExpanded() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
+ shadeExpansionStateFlow.value = 0f
+
+ whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(4)
+ values.forEach { assertThat(it).isEqualTo(ScrimAlpha()) }
+ }
+
+ @Test
+ fun scrimBehindAlpha_leaveShadeOpen() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
+
+ whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(4)
+ values.forEach {
+ assertThat(it).isEqualTo(ScrimAlpha(notificationsAlpha = 1f, behindAlpha = 1f))
+ }
+ }
+
+ @Test
+ fun scrimBehindAlpha_doNotLeaveShadeOpen() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
+
+ whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(4)
+ values.forEach { assertThat(it.notificationsAlpha).isEqualTo(0f) }
+ values.forEach { assertThat(it.frontAlpha).isEqualTo(0f) }
+ values.forEach { assertThat(it.behindAlpha).isIn(Range.closed(0f, 1f)) }
+ assertThat(values[3].behindAlpha).isEqualTo(0f)
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.GONE,
+ value = value,
+ transitionState = state,
+ ownerName = "PrimaryBouncerToGoneTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index d7802aa..6cab023 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -27,7 +27,6 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -35,6 +34,7 @@
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
import dagger.Lazy
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
@@ -52,12 +52,16 @@
private lateinit var featureFlags: FakeFeatureFlags
@Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
@Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ @Mock private lateinit var bouncerToGoneFlows: BouncerToGoneFlows
@Mock
private lateinit var keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>
+ private val shadeExpansionStateFlow = MutableStateFlow(0.1f)
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+
repository = FakeKeyguardTransitionRepository()
val featureFlags =
FakeFeatureFlags().apply { set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) }
@@ -74,6 +78,7 @@
primaryBouncerInteractor,
keyguardDismissActionInteractor,
featureFlags,
+ bouncerToGoneFlows,
)
whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false)
@@ -148,59 +153,6 @@
values.forEach { assertThat(it).isEqualTo(1f) }
}
- @Test
- fun scrimAlpha_runDimissFromKeyguard() =
- runTest(UnconfinedTestDispatcher()) {
- val values by collectValues(underTest.scrimAlpha)
-
- whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true)
-
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
- repository.sendTransitionStep(step(0.3f))
- repository.sendTransitionStep(step(0.6f))
- repository.sendTransitionStep(step(1f))
-
- assertThat(values.size).isEqualTo(4)
- values.forEach { assertThat(it).isEqualTo(ScrimAlpha()) }
- }
-
- @Test
- fun scrimBehindAlpha_leaveShadeOpen() =
- runTest(UnconfinedTestDispatcher()) {
- val values by collectValues(underTest.scrimAlpha)
-
- whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true)
-
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
- repository.sendTransitionStep(step(0.3f))
- repository.sendTransitionStep(step(0.6f))
- repository.sendTransitionStep(step(1f))
-
- assertThat(values.size).isEqualTo(4)
- values.forEach {
- assertThat(it).isEqualTo(ScrimAlpha(notificationsAlpha = 1f, behindAlpha = 1f))
- }
- }
-
- @Test
- fun scrimBehindAlpha_doNotLeaveShadeOpen() =
- runTest(UnconfinedTestDispatcher()) {
- val values by collectValues(underTest.scrimAlpha)
-
- whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false)
-
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
- repository.sendTransitionStep(step(0.3f))
- repository.sendTransitionStep(step(0.6f))
- repository.sendTransitionStep(step(1f))
-
- assertThat(values.size).isEqualTo(4)
- values.forEach { assertThat(it.notificationsAlpha).isEqualTo(0f) }
- values.forEach { assertThat(it.frontAlpha).isEqualTo(0f) }
- values.forEach { assertThat(it.behindAlpha).isIn(Range.closed(0f, 1f)) }
- assertThat(values[3].behindAlpha).isEqualTo(0f)
- }
-
private fun step(
value: Float,
state: TransitionState = TransitionState.RUNNING
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
new file mode 100644
index 0000000..429aad1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
@@ -0,0 +1,66 @@
+package com.android.systemui.mediaprojection
+
+import android.media.projection.IMediaProjectionManager
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_APP as METRICS_CREATION_SOURCE_APP
+import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_CAST as METRICS_CREATION_SOURCE_CAST
+import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_SYSTEM_UI_SCREEN_RECORDER as METRICS_CREATION_SOURCE_SYSTEM_UI_SCREEN_RECORDER
+import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN as METRICS_CREATION_SOURCE_UNKNOWN
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.mock
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class MediaProjectionMetricsLoggerTest : SysuiTestCase() {
+
+ private val service = mock<IMediaProjectionManager>()
+ private val logger = MediaProjectionMetricsLogger(service)
+
+ @Test
+ fun notifyProjectionInitiated_sourceApp_forwardsToServiceWithMetricsValue() {
+ val hostUid = 123
+ val sessionCreationSource = SessionCreationSource.APP
+
+ logger.notifyProjectionInitiated(hostUid, sessionCreationSource)
+
+ verify(service).notifyPermissionRequestInitiated(hostUid, METRICS_CREATION_SOURCE_APP)
+ }
+
+ @Test
+ fun notifyProjectionInitiated_sourceCast_forwardsToServiceWithMetricsValue() {
+ val hostUid = 123
+ val sessionCreationSource = SessionCreationSource.CAST
+
+ logger.notifyProjectionInitiated(hostUid, sessionCreationSource)
+
+ verify(service).notifyPermissionRequestInitiated(hostUid, METRICS_CREATION_SOURCE_CAST)
+ }
+
+ @Test
+ fun notifyProjectionInitiated_sourceSysUI_forwardsToServiceWithMetricsValue() {
+ val hostUid = 123
+ val sessionCreationSource = SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER
+
+ logger.notifyProjectionInitiated(hostUid, sessionCreationSource)
+
+ verify(service)
+ .notifyPermissionRequestInitiated(
+ hostUid,
+ METRICS_CREATION_SOURCE_SYSTEM_UI_SCREEN_RECORDER
+ )
+ }
+
+ @Test
+ fun notifyProjectionInitiated_sourceUnknown_forwardsToServiceWithMetricsValue() {
+ val hostUid = 123
+ val sessionCreationSource = SessionCreationSource.UNKNOWN
+
+ logger.notifyProjectionInitiated(hostUid, sessionCreationSource)
+
+ verify(service).notifyPermissionRequestInitiated(hostUid, METRICS_CREATION_SOURCE_UNKNOWN)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index 90d2e78..c439cfe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -23,11 +23,13 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Dialog;
import android.app.PendingIntent;
+import android.content.Context;
import android.content.Intent;
import android.os.Looper;
import android.testing.AndroidTestingRunner;
@@ -64,6 +66,8 @@
*/
public class RecordingControllerTest extends SysuiTestCase {
+ private static final int TEST_USER_ID = 12345;
+
private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@Mock
@@ -91,6 +95,11 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ Context spiedContext = spy(mContext);
+ when(spiedContext.getUserId()).thenReturn(TEST_USER_ID);
+
+ when(mUserContextProvider.getUserContext()).thenReturn(spiedContext);
+
mFeatureFlags = new FakeFeatureFlags();
mController = new RecordingController(
mMainExecutor,
@@ -288,7 +297,6 @@
if (Looper.myLooper() == null) {
Looper.prepare();
}
-
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING, true);
mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, true);
when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false);
@@ -297,6 +305,8 @@
mDialogLaunchAnimator, mActivityStarter, /* onStartRecordingClicked= */ null);
verify(mMediaProjectionMetricsLogger)
- .notifyProjectionInitiated(SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);
+ .notifyProjectionInitiated(
+ TEST_USER_ID,
+ SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index a5f5fc7..43adc69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -22,14 +22,18 @@
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
import static android.os.UserHandle.USER_ALL;
import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS;
import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -99,6 +103,7 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
+ private static final int TEST_PROFILE_USERHANDLE = 12;
@Mock
private NotificationPresenter mPresenter;
@Mock
@@ -701,6 +706,60 @@
assertFalse(mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(newUserId));
}
+ @Test
+ public void testProfileAvailabilityIntent() {
+ mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
+ mLockscreenUserManager.mCurrentProfiles.clear();
+ assertEquals(0, mLockscreenUserManager.mCurrentProfiles.size());
+ mLockscreenUserManager.mCurrentProfiles.append(0, mock(UserInfo.class));
+ simulateProfileAvailabilityActions(Intent.ACTION_PROFILE_AVAILABLE);
+ assertEquals(2, mLockscreenUserManager.mCurrentProfiles.size());
+ }
+
+ @Test
+ public void testProfileUnAvailabilityIntent() {
+ mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
+ mLockscreenUserManager.mCurrentProfiles.clear();
+ assertEquals(0, mLockscreenUserManager.mCurrentProfiles.size());
+ mLockscreenUserManager.mCurrentProfiles.append(0, mock(UserInfo.class));
+ simulateProfileAvailabilityActions(Intent.ACTION_PROFILE_UNAVAILABLE);
+ assertEquals(2, mLockscreenUserManager.mCurrentProfiles.size());
+ }
+
+ @Test
+ public void testManagedProfileAvailabilityIntent() {
+ mSetFlagsRule.disableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
+ mLockscreenUserManager.mCurrentProfiles.clear();
+ mLockscreenUserManager.mCurrentManagedProfiles.clear();
+ assertEquals(0, mLockscreenUserManager.mCurrentProfiles.size());
+ assertEquals(0, mLockscreenUserManager.mCurrentManagedProfiles.size());
+ mLockscreenUserManager.mCurrentProfiles.append(0, mock(UserInfo.class));
+ simulateProfileAvailabilityActions(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ assertEquals(2, mLockscreenUserManager.mCurrentProfiles.size());
+ assertEquals(1, mLockscreenUserManager.mCurrentManagedProfiles.size());
+ }
+
+ @Test
+ public void testManagedProfileUnAvailabilityIntent() {
+ mSetFlagsRule.disableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
+ mLockscreenUserManager.mCurrentProfiles.clear();
+ mLockscreenUserManager.mCurrentManagedProfiles.clear();
+ assertEquals(0, mLockscreenUserManager.mCurrentProfiles.size());
+ assertEquals(0, mLockscreenUserManager.mCurrentManagedProfiles.size());
+ mLockscreenUserManager.mCurrentProfiles.append(0, mock(UserInfo.class));
+ simulateProfileAvailabilityActions(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ assertEquals(2, mLockscreenUserManager.mCurrentProfiles.size());
+ assertEquals(1, mLockscreenUserManager.mCurrentManagedProfiles.size());
+ }
+
+ private void simulateProfileAvailabilityActions(String intentAction) {
+ BroadcastReceiver broadcastReceiver =
+ mLockscreenUserManager.getBaseBroadcastReceiverForTest();
+ final Intent intent = new Intent(intentAction);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, TEST_PROFILE_USERHANDLE);
+ broadcastReceiver.onReceive(mContext, intent);
+ }
+
private class TestNotificationLockscreenUserManager
extends NotificationLockscreenUserManagerImpl {
public TestNotificationLockscreenUserManager(Context context) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
deleted file mode 100644
index cfcf425..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2023 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
-
-import android.testing.AndroidTestingRunner
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.util.mockito.whenever
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.anyBoolean
-import org.mockito.Mockito.doCallRealMethod
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-/**
- * Temporary test for the lock screen live wallpaper project.
- *
- * TODO(b/273443374): remove this test
- */
-@RunWith(AndroidTestingRunner::class)
-@SmallTest
-class NotificationMediaManagerTest : SysuiTestCase() {
-
- @Mock private lateinit var notificationMediaManager: NotificationMediaManager
-
- @Mock private lateinit var mockBackDropView: BackDropView
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- doCallRealMethod().whenever(notificationMediaManager).updateMediaMetaData(anyBoolean())
- doReturn(mockBackDropView).whenever(notificationMediaManager).backDropView
- }
-
- @After fun tearDown() {}
-
- /** Check that updateMediaMetaData is a no-op with mIsLockscreenLiveWallpaperEnabled = true */
- @Test
- fun testUpdateMediaMetaDataDisabled() {
- notificationMediaManager.mIsLockscreenLiveWallpaperEnabled = true
- for (metaDataChanged in listOf(true, false)) {
- for (allowEnterAnimation in listOf(true, false)) {
- notificationMediaManager.updateMediaMetaData(metaDataChanged)
- verify(notificationMediaManager, never()).mediaMetadata
- }
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt
index 8397702..df8afde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/FakeStatusEvent.kt
@@ -26,6 +26,7 @@
override var forceVisible: Boolean = false,
override val showAnimation: Boolean = true,
override var contentDescription: String? = "",
+ override val shouldAnnounceAccessibilityEvent: Boolean = false
) : StatusEvent
class FakePrivacyStatusEvent(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
index 4fcccf8..fee8b82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
@@ -33,6 +33,8 @@
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import junit.framework.Assert.assertEquals
@@ -370,6 +372,63 @@
}
@Test
+ fun testAccessibilityAnnouncement_announced() = runTest {
+ // Instantiate class under test with TestScope from runTest
+ initializeSystemStatusAnimationScheduler(testScope = this)
+ val accessibilityDesc = "Some desc"
+ val mockView = mock<View>()
+ val mockAnimatableView =
+ mock<BackgroundAnimatableView> { whenever(view).thenReturn(mockView) }
+
+ scheduleFakeEventWithView(
+ accessibilityDesc,
+ mockAnimatableView,
+ shouldAnnounceAccessibilityEvent = true
+ )
+ fastForwardAnimationToState(ANIMATING_OUT)
+
+ verify(mockView).announceForAccessibility(eq(accessibilityDesc))
+ }
+
+ @Test
+ fun testAccessibilityAnnouncement_nullDesc_noAnnouncement() = runTest {
+ // Instantiate class under test with TestScope from runTest
+ initializeSystemStatusAnimationScheduler(testScope = this)
+ val accessibilityDesc = null
+ val mockView = mock<View>()
+ val mockAnimatableView =
+ mock<BackgroundAnimatableView> { whenever(view).thenReturn(mockView) }
+
+ scheduleFakeEventWithView(
+ accessibilityDesc,
+ mockAnimatableView,
+ shouldAnnounceAccessibilityEvent = true
+ )
+ fastForwardAnimationToState(ANIMATING_OUT)
+
+ verify(mockView, never()).announceForAccessibility(any())
+ }
+
+ @Test
+ fun testAccessibilityAnnouncement_notNeeded_noAnnouncement() = runTest {
+ // Instantiate class under test with TestScope from runTest
+ initializeSystemStatusAnimationScheduler(testScope = this)
+ val accessibilityDesc = "something"
+ val mockView = mock<View>()
+ val mockAnimatableView =
+ mock<BackgroundAnimatableView> { whenever(view).thenReturn(mockView) }
+
+ scheduleFakeEventWithView(
+ accessibilityDesc,
+ mockAnimatableView,
+ shouldAnnounceAccessibilityEvent = false
+ )
+ fastForwardAnimationToState(ANIMATING_OUT)
+
+ verify(mockView, never()).announceForAccessibility(any())
+ }
+
+ @Test
fun testPrivacyDot_isRemovedDuringChipAnimation() = runTest {
// Instantiate class under test with TestScope from runTest
initializeSystemStatusAnimationScheduler(testScope = this)
@@ -572,6 +631,20 @@
return privacyChip
}
+ private fun scheduleFakeEventWithView(
+ desc: String?,
+ view: BackgroundAnimatableView,
+ shouldAnnounceAccessibilityEvent: Boolean
+ ) {
+ val fakeEvent =
+ FakeStatusEvent(
+ viewCreator = { view },
+ contentDescription = desc,
+ shouldAnnounceAccessibilityEvent = shouldAnnounceAccessibilityEvent
+ )
+ systemStatusAnimationScheduler.onStatusEvent(fakeEvent)
+ }
+
private fun createAndScheduleFakeBatteryEvent(): BatteryStatusChip {
val batteryChip = BatteryStatusChip(mContext)
val fakeBatteryEvent =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index c8cbe42..a59cd87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -277,8 +277,6 @@
mNotificationShadeWindowViewControllerLazy;
@Mock private NotificationShelfController mNotificationShelfController;
@Mock private DozeParameters mDozeParameters;
- @Mock private Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy;
- @Mock private LockscreenWallpaper mLockscreenWallpaper;
@Mock private DozeServiceHost mDozeServiceHost;
@Mock private BackActionInteractor mBackActionInteractor;
@Mock private ViewMediatorCallback mKeyguardVieMediatorCallback;
@@ -404,7 +402,6 @@
when(mGradientColors.supportsDarkText()).thenReturn(true);
when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
- when(mLockscreenWallpaperLazy.get()).thenReturn(mLockscreenWallpaper);
when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController);
when(mCameraLauncherLazy.get()).thenReturn(mCameraLauncher);
when(mNotificationShadeWindowViewControllerLazy.get())
@@ -508,7 +505,6 @@
new NotificationExpansionRepository(),
mDozeParameters,
mScrimController,
- mLockscreenWallpaperLazy,
mBiometricUnlockControllerLazy,
mAuthRippleController,
mDozeServiceHost,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenWallpaperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenWallpaperTest.kt
deleted file mode 100644
index 47671fb..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenWallpaperTest.kt
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2023 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.phone
-
-import android.app.WallpaperManager
-import android.content.pm.UserInfo
-import android.os.Looper
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.user.data.model.SelectionStatus
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.util.kotlin.JavaAdapter
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
-import com.android.systemui.utils.os.FakeHandler
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mockito.verify
-
-@SmallTest
-@OptIn(ExperimentalCoroutinesApi::class)
-class LockscreenWallpaperTest : SysuiTestCase() {
-
- private lateinit var underTest: LockscreenWallpaper
-
- private val testScope = TestScope(StandardTestDispatcher())
- private val userRepository = FakeUserRepository()
-
- private val wallpaperManager: WallpaperManager = mock()
-
- @Before
- fun setUp() {
- whenever(wallpaperManager.isLockscreenLiveWallpaperEnabled).thenReturn(false)
- whenever(wallpaperManager.isWallpaperSupported).thenReturn(true)
- underTest =
- LockscreenWallpaper(
- /* wallpaperManager= */ wallpaperManager,
- /* iWallpaperManager= */ mock(),
- /* keyguardUpdateMonitor= */ mock(),
- /* dumpManager= */ mock(),
- /* mediaManager= */ mock(),
- /* mainHandler= */ FakeHandler(Looper.getMainLooper()),
- /* javaAdapter= */ JavaAdapter(testScope.backgroundScope),
- /* userRepository= */ userRepository,
- /* userTracker= */ mock(),
- )
- underTest.start()
- }
-
- @Test
- fun getBitmap_matchesUserIdFromUserRepo() =
- testScope.runTest {
- val info = UserInfo(/* id= */ 5, /* name= */ "id5", /* flags= */ 0)
- userRepository.setUserInfos(listOf(info))
- userRepository.setSelectedUserInfo(info)
-
- underTest.bitmap
-
- verify(wallpaperManager).getWallpaperFile(any(), eq(5))
- }
-
- @Test
- fun getBitmap_usesOldUserIfNewUserInProgress() =
- testScope.runTest {
- val info5 = UserInfo(/* id= */ 5, /* name= */ "id5", /* flags= */ 0)
- val info6 = UserInfo(/* id= */ 6, /* name= */ "id6", /* flags= */ 0)
- userRepository.setUserInfos(listOf(info5, info6))
- userRepository.setSelectedUserInfo(info5)
-
- // WHEN the selection of user 6 is only in progress
- userRepository.setSelectedUserInfo(
- info6,
- selectionStatus = SelectionStatus.SELECTION_IN_PROGRESS
- )
-
- underTest.bitmap
-
- // THEN we still use user 5 for wallpaper selection
- verify(wallpaperManager).getWallpaperFile(any(), eq(5))
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 6b3bd22..15c09b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -70,6 +70,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
+import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
@@ -141,6 +142,8 @@
@Mock private ScreenOffAnimationController mScreenOffAnimationController;
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
+ @Mock private AlternateBouncerToGoneTransitionViewModel
+ mAlternateBouncerToGoneTransitionViewModel;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private final FakeWallpaperRepository mWallpaperRepository = new FakeWallpaperRepository();
@Mock private CoroutineDispatcher mMainDispatcher;
@@ -264,10 +267,12 @@
when(mDelayedWakeLockBuilder.build()).thenReturn(mWakeLock);
when(mDockManager.isDocked()).thenReturn(false);
- when(mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition())
+ when(mKeyguardTransitionInteractor.transition(any(), any()))
.thenReturn(emptyFlow());
when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha())
.thenReturn(emptyFlow());
+ when(mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha())
+ .thenReturn(emptyFlow());
mScrimController = new ScrimController(
mLightBarController,
@@ -285,6 +290,7 @@
mKeyguardUnlockAnimationController,
mStatusBarKeyguardViewManager,
mPrimaryBouncerToGoneTransitionViewModel,
+ mAlternateBouncerToGoneTransitionViewModel,
mKeyguardTransitionInteractor,
mWallpaperRepository,
mMainDispatcher,
@@ -992,6 +998,7 @@
mKeyguardUnlockAnimationController,
mStatusBarKeyguardViewManager,
mPrimaryBouncerToGoneTransitionViewModel,
+ mAlternateBouncerToGoneTransitionViewModel,
mKeyguardTransitionInteractor,
mWallpaperRepository,
mMainDispatcher,
@@ -1775,7 +1782,7 @@
@Test
public void ignoreTransitionRequestWhileKeyguardTransitionRunning() {
mScrimController.transitionTo(ScrimState.UNLOCKED);
- mScrimController.mPrimaryBouncerToGoneTransition.accept(
+ mScrimController.mBouncerToGoneTransition.accept(
new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
TransitionState.RUNNING, "ScrimControllerTest"));
@@ -1787,7 +1794,7 @@
@Test
public void primaryBouncerToGoneOnFinishCallsKeyguardFadedAway() {
when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true);
- mScrimController.mPrimaryBouncerToGoneTransition.accept(
+ mScrimController.mBouncerToGoneTransition.accept(
new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
TransitionState.FINISHED, "ScrimControllerTest"));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
new file mode 100644
index 0000000..21d22bc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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.phone
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import kotlin.test.Test
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class SystemUIBottomSheetDialogTest : SysuiTestCase() {
+
+ private val configurationController = mock<ConfigurationController>()
+
+ private lateinit var dialog: SystemUIBottomSheetDialog
+
+ @Before
+ fun setup() {
+ dialog = SystemUIBottomSheetDialog(mContext, configurationController)
+ }
+
+ @Test
+ fun onStart_registersConfigCallback() {
+ dialog.show()
+
+ verify(configurationController).addCallback(any())
+ }
+
+ @Test
+ fun onStop_unregisterConfigCallback() {
+ dialog.show()
+ dialog.dismiss()
+
+ verify(configurationController).removeCallback(any())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceStateRepositoryTest.kt
new file mode 100644
index 0000000..4eb1591
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceStateRepositoryTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 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.unfold.updates
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.unfold.system.DeviceStateRepositoryImpl
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class DeviceStateRepositoryTest : SysuiTestCase() {
+
+ private val foldProvider = mock<FoldProvider>()
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+
+ private val foldStateRepository = DeviceStateRepositoryImpl(foldProvider) { r -> r.run() }
+
+ @Test
+ fun onHingeAngleUpdate_received() =
+ testScope.runTest {
+ val flowValue = collectLastValue(foldStateRepository.isFolded)
+ val foldCallback = argumentCaptor<FoldProvider.FoldCallback>()
+
+ verify(foldProvider).registerCallback(capture(foldCallback), any())
+
+ foldCallback.value.onFoldUpdated(true)
+ assertThat(flowValue()).isEqualTo(true)
+
+ foldCallback.value.onFoldUpdated(false)
+ assertThat(flowValue()).isEqualTo(false)
+ }
+
+ @Test
+ fun onHingeAngleUpdate_unregisters() {
+ testScope.runTest {
+ val flowValue = collectLastValue(foldStateRepository.isFolded)
+
+ verify(foldProvider).registerCallback(any(), any())
+ }
+ verify(foldProvider).unregisterCallback(any())
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/FoldStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/FoldStateRepositoryTest.kt
new file mode 100644
index 0000000..0651323
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/FoldStateRepositoryTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2023 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.unfold.updates
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.unfold.updates.FoldStateRepository.FoldUpdate
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class FoldStateRepositoryTest : SysuiTestCase() {
+
+ private val foldStateProvider = mock<FoldStateProvider>()
+ private val foldUpdatesListener = argumentCaptor<FoldStateProvider.FoldUpdatesListener>()
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+
+ private val foldStateRepository = FoldStateRepositoryImpl(foldStateProvider)
+ @Test
+ fun onHingeAngleUpdate_received() =
+ testScope.runTest {
+ val flowValue = collectLastValue(foldStateRepository.hingeAngle)
+
+ verify(foldStateProvider).addCallback(capture(foldUpdatesListener))
+ foldUpdatesListener.value.onHingeAngleUpdate(42f)
+
+ assertThat(flowValue()).isEqualTo(42f)
+ }
+
+ @Test
+ fun onFoldUpdate_received() =
+ testScope.runTest {
+ val flowValue = collectLastValue(foldStateRepository.foldUpdate)
+
+ verify(foldStateProvider).addCallback(capture(foldUpdatesListener))
+ foldUpdatesListener.value.onFoldUpdate(FOLD_UPDATE_START_OPENING)
+
+ assertThat(flowValue()).isEqualTo(FoldUpdate.START_OPENING)
+ }
+
+ @Test
+ fun foldUpdates_mappedCorrectly() {
+ mapOf(
+ FOLD_UPDATE_START_OPENING to FoldUpdate.START_OPENING,
+ FOLD_UPDATE_START_CLOSING to FoldUpdate.START_CLOSING,
+ FOLD_UPDATE_FINISH_HALF_OPEN to FoldUpdate.FINISH_HALF_OPEN,
+ FOLD_UPDATE_FINISH_FULL_OPEN to FoldUpdate.FINISH_FULL_OPEN,
+ FOLD_UPDATE_FINISH_CLOSED to FoldUpdate.FINISH_CLOSED
+ )
+ .forEach { (id, expected) ->
+ assertThat(FoldUpdate.fromFoldUpdateId(id)).isEqualTo(expected)
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index 468c5a7..fc2030f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -16,15 +16,20 @@
package com.android.systemui.wallpapers;
+import static android.app.WallpaperManager.FLAG_LOCK;
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -111,7 +116,8 @@
when(mWallpaperBitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888);
// set up wallpaper manager
- when(mWallpaperManager.getBitmapAsUser(eq(ActivityManager.getCurrentUser()), anyBoolean()))
+ when(mWallpaperManager.getBitmapAsUser(
+ eq(ActivityManager.getCurrentUser()), anyBoolean(), anyInt(), anyBoolean()))
.thenReturn(mWallpaperBitmap);
when(mMockContext.getSystemService(WallpaperManager.class)).thenReturn(mWallpaperManager);
@@ -208,6 +214,7 @@
ImageWallpaper.CanvasEngine spyEngine = spy(engine);
doNothing().when(spyEngine).drawFrameOnCanvas(any(Bitmap.class));
doNothing().when(spyEngine).reportEngineShown(anyBoolean());
+ doReturn(FLAG_SYSTEM | FLAG_LOCK).when(spyEngine).getWallpaperFlags();
doAnswer(invocation -> {
((ImageWallpaper.CanvasEngine) invocation.getMock()).onMiniBitmapUpdated();
return null;
@@ -216,7 +223,7 @@
}
private void setBitmapDimensions(int bitmapWidth, int bitmapHeight) {
- when(mWallpaperManager.peekBitmapDimensions())
+ when(mWallpaperManager.peekBitmapDimensions(anyInt(), anyBoolean()))
.thenReturn(new Rect(0, 0, bitmapWidth, bitmapHeight));
when(mWallpaperBitmap.getWidth()).thenReturn(bitmapWidth);
when(mWallpaperBitmap.getHeight()).thenReturn(bitmapHeight);
@@ -234,9 +241,7 @@
clearInvocations(mSurfaceHolder);
setBitmapDimensions(bitmapWidth, bitmapHeight);
- ImageWallpaper imageWallpaper = createImageWallpaper();
- ImageWallpaper.CanvasEngine engine =
- (ImageWallpaper.CanvasEngine) imageWallpaper.onCreateEngine();
+ ImageWallpaper.CanvasEngine engine = getSpyEngine();
engine.onCreate(mSurfaceHolder);
verify(mSurfaceHolder, times(1)).setFixedSize(
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
index 5ffc094..7473ca6 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
@@ -22,6 +22,8 @@
import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder
import com.android.systemui.unfold.updates.DeviceFoldStateProvider
import com.android.systemui.unfold.updates.FoldStateProvider
+import com.android.systemui.unfold.updates.FoldStateRepository
+import com.android.systemui.unfold.updates.FoldStateRepositoryImpl
import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider
import com.android.systemui.unfold.updates.hinge.HingeAngleProvider
import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider
@@ -55,6 +57,12 @@
fun unfoldKeyguardVisibilityManager(
impl: UnfoldKeyguardVisibilityManagerImpl
): UnfoldKeyguardVisibilityManager = impl
+
+ @Provides
+ @Singleton
+ fun foldStateRepository(
+ impl: FoldStateRepositoryImpl
+ ): FoldStateRepository = impl
}
/**
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 6743515..003013e 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -17,7 +17,6 @@
import android.content.Context
import android.os.Handler
-import android.os.Trace
import android.util.Log
import androidx.annotation.FloatRange
import androidx.annotation.VisibleForTesting
@@ -130,7 +129,6 @@
"lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition"
)
}
- Trace.setCounter("DeviceFoldStateProvider#onHingeAngle", angle.toLong())
val currentDirection =
if (angle < lastHingeAngle) FOLD_UPDATE_START_CLOSING else FOLD_UPDATE_START_OPENING
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldProvider.kt
index 6e87bee..ea6786e 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldProvider.kt
@@ -20,7 +20,7 @@
fun registerCallback(callback: FoldCallback, executor: Executor)
fun unregisterCallback(callback: FoldCallback)
- interface FoldCallback {
+ fun interface FoldCallback {
fun onFoldUpdated(isFolded: Boolean)
}
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateRepository.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateRepository.kt
new file mode 100644
index 0000000..61b0b40
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateRepository.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 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.unfold.updates
+
+import com.android.systemui.unfold.updates.FoldStateRepository.FoldUpdate
+import javax.inject.Inject
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.buffer
+import kotlinx.coroutines.flow.callbackFlow
+
+/**
+ * Allows to subscribe to main events related to fold/unfold process such as hinge angle update,
+ * start folding/unfolding, screen availability
+ */
+interface FoldStateRepository {
+ /** Latest fold update, as described by [FoldStateProvider.FoldUpdate]. */
+ val foldUpdate: Flow<FoldUpdate>
+
+ /** Provides the hinge angle while the fold/unfold is in progress. */
+ val hingeAngle: Flow<Float>
+
+ enum class FoldUpdate {
+ START_OPENING,
+ START_CLOSING,
+ FINISH_HALF_OPEN,
+ FINISH_FULL_OPEN,
+ FINISH_CLOSED;
+
+ companion object {
+ /** Maps the old [FoldStateProvider.FoldUpdate] to [FoldStateRepository.FoldUpdate]. */
+ fun fromFoldUpdateId(@FoldStateProvider.FoldUpdate oldId: Int): FoldUpdate {
+ return when (oldId) {
+ FOLD_UPDATE_START_OPENING -> START_OPENING
+ FOLD_UPDATE_START_CLOSING -> START_CLOSING
+ FOLD_UPDATE_FINISH_HALF_OPEN -> FINISH_HALF_OPEN
+ FOLD_UPDATE_FINISH_FULL_OPEN -> FINISH_FULL_OPEN
+ FOLD_UPDATE_FINISH_CLOSED -> FINISH_CLOSED
+ else -> error("FoldUpdateNotFound")
+ }
+ }
+ }
+ }
+}
+
+class FoldStateRepositoryImpl
+@Inject
+constructor(
+ private val foldStateProvider: FoldStateProvider,
+) : FoldStateRepository {
+
+ override val hingeAngle: Flow<Float>
+ get() =
+ callbackFlow {
+ val callback =
+ object : FoldStateProvider.FoldUpdatesListener {
+ override fun onHingeAngleUpdate(angle: Float) {
+ trySend(angle)
+ }
+ }
+ foldStateProvider.addCallback(callback)
+ awaitClose { foldStateProvider.removeCallback(callback) }
+ }
+ .buffer(capacity = Channel.CONFLATED)
+
+ override val foldUpdate: Flow<FoldUpdate>
+ get() =
+ callbackFlow {
+ val callback =
+ object : FoldStateProvider.FoldUpdatesListener {
+ override fun onFoldUpdate(update: Int) {
+ trySend(FoldUpdate.fromFoldUpdateId(update))
+ }
+ }
+ foldStateProvider.addCallback(callback)
+ awaitClose { foldStateProvider.removeCallback(callback) }
+ }
+ .buffer(capacity = Channel.CONFLATED)
+}
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 3406102..98421a9 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -367,11 +367,7 @@
ComponentName wpService = parseWallpaperComponent(infoStage, "wp");
mSystemHasLiveComponent = wpService != null;
- ComponentName kwpService = null;
- boolean lockscreenLiveWallpaper = mWallpaperManager.isLockscreenLiveWallpaperEnabled();
- if (lockscreenLiveWallpaper) {
- kwpService = parseWallpaperComponent(infoStage, "kwp");
- }
+ ComponentName kwpService = parseWallpaperComponent(infoStage, "kwp");
mLockHasLiveComponent = kwpService != null;
boolean separateLockWallpaper = mLockHasLiveComponent || lockImageStage.exists();
@@ -381,17 +377,16 @@
// It is valid for the imagery to be absent; it means that we were not permitted
// to back up the original image on the source device, or there was no user-supplied
// wallpaper image present.
- if (!lockscreenLiveWallpaper) restoreFromStage(imageStage, infoStage, "wp", sysWhich);
if (lockImageStageExists) {
restoreFromStage(lockImageStage, infoStage, "kwp", FLAG_LOCK);
}
- if (lockscreenLiveWallpaper) restoreFromStage(imageStage, infoStage, "wp", sysWhich);
+ restoreFromStage(imageStage, infoStage, "wp", sysWhich);
// And reset to the wallpaper service we should be using
- if (lockscreenLiveWallpaper && mLockHasLiveComponent) {
- updateWallpaperComponent(kwpService, false, FLAG_LOCK);
+ if (mLockHasLiveComponent) {
+ updateWallpaperComponent(kwpService, FLAG_LOCK);
}
- updateWallpaperComponent(wpService, !lockImageStageExists, sysWhich);
+ updateWallpaperComponent(wpService, sysWhich);
} catch (Exception e) {
Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage());
mEventLogger.onRestoreException(e);
@@ -410,36 +405,24 @@
}
@VisibleForTesting
- void updateWallpaperComponent(ComponentName wpService, boolean applyToLock, int which)
+ void updateWallpaperComponent(ComponentName wpService, int which)
throws IOException {
- boolean lockscreenLiveWallpaper = mWallpaperManager.isLockscreenLiveWallpaperEnabled();
if (servicePackageExists(wpService)) {
Slog.i(TAG, "Using wallpaper service " + wpService);
- if (lockscreenLiveWallpaper) {
- mWallpaperManager.setWallpaperComponentWithFlags(wpService, which);
- if ((which & FLAG_LOCK) != 0) {
- mEventLogger.onLockLiveWallpaperRestored(wpService);
- }
- if ((which & FLAG_SYSTEM) != 0) {
- mEventLogger.onSystemLiveWallpaperRestored(wpService);
- }
- return;
- }
- mWallpaperManager.setWallpaperComponent(wpService);
- if (applyToLock) {
- // We have a live wallpaper and no static lock image,
- // allow live wallpaper to show "through" on lock screen.
- mWallpaperManager.clear(FLAG_LOCK);
+ mWallpaperManager.setWallpaperComponentWithFlags(wpService, which);
+ if ((which & FLAG_LOCK) != 0) {
mEventLogger.onLockLiveWallpaperRestored(wpService);
}
- mEventLogger.onSystemLiveWallpaperRestored(wpService);
+ if ((which & FLAG_SYSTEM) != 0) {
+ mEventLogger.onSystemLiveWallpaperRestored(wpService);
+ }
} else {
// If we've restored a live wallpaper, but the component doesn't exist,
// we should log it as an error so we can easily identify the problem
// in reports from users
if (wpService != null) {
// TODO(b/268471749): Handle delayed case
- applyComponentAtInstall(wpService, applyToLock, which);
+ applyComponentAtInstall(wpService, which);
Slog.w(TAG, "Wallpaper service " + wpService + " isn't available. "
+ " Will try to apply later");
}
@@ -579,21 +562,17 @@
// Intentionally blank
}
- private void applyComponentAtInstall(ComponentName componentName, boolean applyToLock,
- int which) {
+ private void applyComponentAtInstall(ComponentName componentName, int which) {
PackageMonitor packageMonitor = getWallpaperPackageMonitor(
- componentName, applyToLock, which);
+ componentName, which);
packageMonitor.register(getBaseContext(), null, UserHandle.ALL, true);
}
@VisibleForTesting
- PackageMonitor getWallpaperPackageMonitor(ComponentName componentName, boolean applyToLock,
- int which) {
+ PackageMonitor getWallpaperPackageMonitor(ComponentName componentName, int which) {
return new PackageMonitor() {
@Override
public void onPackageAdded(String packageName, int uid) {
- boolean lockscreenLiveWallpaper =
- mWallpaperManager.isLockscreenLiveWallpaperEnabled();
if (!isDeviceInRestore()) {
// We don't want to reapply the wallpaper outside a restore.
unregister();
@@ -601,9 +580,11 @@
// We have finished restore and not succeeded, so let's log that as an error.
WallpaperEventLogger logger = new WallpaperEventLogger(
mBackupManager.getDelayedRestoreLogger());
- logger.onSystemLiveWallpaperRestoreFailed(
- WallpaperEventLogger.ERROR_LIVE_PACKAGE_NOT_INSTALLED);
- if (applyToLock) {
+ if ((which & FLAG_SYSTEM) != 0) {
+ logger.onSystemLiveWallpaperRestoreFailed(
+ WallpaperEventLogger.ERROR_LIVE_PACKAGE_NOT_INSTALLED);
+ }
+ if ((which & FLAG_LOCK) != 0) {
logger.onLockLiveWallpaperRestoreFailed(
WallpaperEventLogger.ERROR_LIVE_PACKAGE_NOT_INSTALLED);
}
@@ -614,37 +595,27 @@
if (componentName.getPackageName().equals(packageName)) {
Slog.d(TAG, "Applying component " + componentName);
- boolean success = lockscreenLiveWallpaper
- ? mWallpaperManager.setWallpaperComponentWithFlags(componentName, which)
- : mWallpaperManager.setWallpaperComponent(componentName);
+ boolean success = mWallpaperManager.setWallpaperComponentWithFlags(
+ componentName, which);
WallpaperEventLogger logger = new WallpaperEventLogger(
mBackupManager.getDelayedRestoreLogger());
if (success) {
- if (!lockscreenLiveWallpaper || (which & FLAG_SYSTEM) != 0) {
+ if ((which & FLAG_SYSTEM) != 0) {
logger.onSystemLiveWallpaperRestored(componentName);
}
- if (lockscreenLiveWallpaper && (which & FLAG_LOCK) != 0) {
+ if ((which & FLAG_LOCK) != 0) {
logger.onLockLiveWallpaperRestored(componentName);
}
} else {
- if (!lockscreenLiveWallpaper || (which & FLAG_SYSTEM) != 0) {
+ if ((which & FLAG_SYSTEM) != 0) {
logger.onSystemLiveWallpaperRestoreFailed(
WallpaperEventLogger.ERROR_SET_COMPONENT_EXCEPTION);
}
- if (lockscreenLiveWallpaper && (which & FLAG_LOCK) != 0) {
+ if ((which & FLAG_LOCK) != 0) {
logger.onLockLiveWallpaperRestoreFailed(
WallpaperEventLogger.ERROR_SET_COMPONENT_EXCEPTION);
}
}
- if (applyToLock && !lockscreenLiveWallpaper) {
- try {
- mWallpaperManager.clear(FLAG_LOCK);
- logger.onLockLiveWallpaperRestored(componentName);
- } catch (IOException e) {
- Slog.w(TAG, "Failed to apply live wallpaper to lock screen: " + e);
- logger.onLockLiveWallpaperRestoreFailed(e.getClass().getName());
- }
- }
// We're only expecting to restore the wallpaper component once.
unregister();
mBackupManager.reportDelayedRestoreResult(logger.getBackupRestoreLogger());
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
index dc1126e..4c224fb 100644
--- a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
@@ -116,8 +116,6 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
-
- when(mWallpaperManager.isLockscreenLiveWallpaperEnabled()).thenReturn(true);
when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_SYSTEM))).thenReturn(true);
when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_LOCK))).thenReturn(true);
@@ -363,25 +361,19 @@
@Test
public void testUpdateWallpaperComponent_doesApplyLater() throws IOException {
mWallpaperBackupAgent.mIsDeviceInRestore = true;
-
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
+ /* which */ FLAG_LOCK | FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
/* uid */0);
- if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
- verify(mWallpaperManager, times(1))
- .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK | FLAG_SYSTEM);
- verify(mWallpaperManager, never())
- .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_SYSTEM);
- verify(mWallpaperManager, never())
- .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK);
- verify(mWallpaperManager, never()).clear(anyInt());
- } else {
- verify(mWallpaperManager, times(1)).setWallpaperComponent(mWallpaperComponent);
- verify(mWallpaperManager, times(1)).clear(eq(FLAG_LOCK));
- }
+ verify(mWallpaperManager, times(1))
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK | FLAG_SYSTEM);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_SYSTEM);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK);
+ verify(mWallpaperManager, never()).clear(anyInt());
}
@Test
@@ -390,24 +382,19 @@
mWallpaperBackupAgent.mIsDeviceInRestore = true;
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ false, FLAG_SYSTEM);
+ /* which */ FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
/* uid */0);
- if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
- verify(mWallpaperManager, times(1))
- .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_SYSTEM);
- verify(mWallpaperManager, never())
- .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK);
- verify(mWallpaperManager, never())
- .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK | FLAG_SYSTEM);
- verify(mWallpaperManager, never()).clear(anyInt());
- } else {
- verify(mWallpaperManager, times(1)).setWallpaperComponent(mWallpaperComponent);
- verify(mWallpaperManager, never()).clear(eq(FLAG_LOCK));
- }
+ verify(mWallpaperManager, times(1))
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_SYSTEM);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK);
+ verify(mWallpaperManager, never())
+ .setWallpaperComponentWithFlags(mWallpaperComponent, FLAG_LOCK | FLAG_SYSTEM);
+ verify(mWallpaperManager, never()).clear(anyInt());
}
@Test
@@ -416,7 +403,7 @@
mWallpaperBackupAgent.mIsDeviceInRestore = false;
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
+ /* which */ FLAG_LOCK | FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
@@ -432,7 +419,7 @@
mWallpaperBackupAgent.mIsDeviceInRestore = false;
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
+ /* which */ FLAG_LOCK | FLAG_SYSTEM);
// Imitate "wrong" wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(/* packageName */"",
@@ -622,7 +609,7 @@
}
@Test
- public void testOnRestore_systemWallpaperImgSuccess_logsSuccess() throws Exception {
+ public void testOnRestore_wallpaperImgSuccess_logsSuccess() throws Exception {
mockStagedWallpaperFile(WALLPAPER_INFO_STAGE);
mockStagedWallpaperFile(SYSTEM_WALLPAPER_STAGE);
mWallpaperBackupAgent.onCreate(USER_HANDLE, BackupAnnotations.BackupDestination.CLOUD,
@@ -630,17 +617,16 @@
mWallpaperBackupAgent.onRestoreFinished();
+ // wallpaper will be applied to home & lock screen, a success for both screens in expected
DataTypeResult result = getLoggingResult(WALLPAPER_IMG_SYSTEM,
mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
assertThat(result).isNotNull();
assertThat(result.getSuccessCount()).isEqualTo(1);
- if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
- result = getLoggingResult(WALLPAPER_IMG_LOCK,
- mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
- assertThat(result).isNotNull();
- assertThat(result.getSuccessCount()).isEqualTo(1);
- }
+ result = getLoggingResult(WALLPAPER_IMG_LOCK,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getSuccessCount()).isEqualTo(1);
}
@Test
@@ -758,7 +744,7 @@
mWallpaperBackupAgent.setBackupManagerForTesting(mBackupManager);
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
+ /* which */ FLAG_LOCK | FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
/* uid */0);
@@ -782,7 +768,7 @@
mWallpaperBackupAgent.setBackupManagerForTesting(mBackupManager);
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
+ /* which */ FLAG_LOCK | FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
/* uid */0);
@@ -804,7 +790,7 @@
mWallpaperBackupAgent.setBackupManagerForTesting(mBackupManager);
mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
- /* applyToLock */ true, FLAG_LOCK | FLAG_SYSTEM);
+ /* which */ FLAG_LOCK | FLAG_SYSTEM);
// Imitate wallpaper component installation.
mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
@@ -938,10 +924,8 @@
}
@Override
- PackageMonitor getWallpaperPackageMonitor(ComponentName componentName,
- boolean applyToLock, int which) {
- mWallpaperPackageMonitor = super.getWallpaperPackageMonitor(
- componentName, applyToLock, which);
+ PackageMonitor getWallpaperPackageMonitor(ComponentName componentName, int which) {
+ mWallpaperPackageMonitor = super.getWallpaperPackageMonitor(componentName, which);
return mWallpaperPackageMonitor;
}
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 1a735f8..75ecdb7 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -1,32 +1,6 @@
package: "com.android.server.accessibility"
-flag {
- name: "proxy_use_apps_on_virtual_device_listener"
- namespace: "accessibility"
- description: "Fixes race condition described in b/286587811"
- bug: "286587811"
-}
-
-flag {
- name: "enable_magnification_multiple_finger_multiple_tap_gesture"
- namespace: "accessibility"
- description: "Whether to enable multi-finger-multi-tap gesture for magnification"
- bug: "257274411"
-}
-
-flag {
- name: "enable_magnification_joystick"
- namespace: "accessibility"
- description: "Whether to enable joystick controls for magnification"
- bug: "297211257"
-}
-
-flag {
- name: "send_a11y_events_based_on_state"
- namespace: "accessibility"
- description: "Sends accessibility events in TouchExplorer#onAccessibilityEvent based on internal state to keep it consistent. This reduces test flakiness."
- bug: "295575684"
-}
+# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
flag {
name: "add_window_token_without_lock"
@@ -36,20 +10,6 @@
}
flag {
- name: "pinch_zoom_zero_min_span"
- namespace: "accessibility"
- description: "Whether to set min span of ScaleGestureDetector to zero."
- bug: "295327792"
-}
-
-flag {
- name: "disable_continuous_shortcut_on_force_stop"
- namespace: "accessibility"
- description: "When a package is force stopped, remove the button shortcuts of any continuously-running shortcuts."
- bug: "198018180"
-}
-
-flag {
name: "deprecate_package_list_observer"
namespace: "accessibility"
description: "Stops using the deprecated PackageListObserver."
@@ -57,10 +17,38 @@
}
flag {
- name: "scan_packages_without_lock"
+ name: "disable_continuous_shortcut_on_force_stop"
namespace: "accessibility"
- description: "Scans packages for accessibility service/activity info without holding the A11yMS lock"
- bug: "295969873"
+ description: "When a package is force stopped, remove the button shortcuts of any continuously-running shortcuts."
+ bug: "198018180"
+}
+
+flag {
+ name: "enable_magnification_joystick"
+ namespace: "accessibility"
+ description: "Whether to enable joystick controls for magnification"
+ bug: "297211257"
+}
+
+flag {
+ name: "enable_magnification_multiple_finger_multiple_tap_gesture"
+ namespace: "accessibility"
+ description: "Whether to enable multi-finger-multi-tap gesture for magnification"
+ bug: "257274411"
+}
+
+flag {
+ name: "pinch_zoom_zero_min_span"
+ namespace: "accessibility"
+ description: "Whether to set min span of ScaleGestureDetector to zero."
+ bug: "295327792"
+}
+
+flag {
+ name: "proxy_use_apps_on_virtual_device_listener"
+ namespace: "accessibility"
+ description: "Fixes race condition described in b/286587811"
+ bug: "286587811"
}
flag {
@@ -69,3 +57,17 @@
description: "Reduces touch exploration sensitivity by only sending a hover event when the ifnger has moved the amount of pixels defined by the system's touch slop."
bug: "303677860"
}
+
+flag {
+ name: "scan_packages_without_lock"
+ namespace: "accessibility"
+ description: "Scans packages for accessibility service/activity info without holding the A11yMS lock"
+ bug: "295969873"
+}
+
+flag {
+ name: "send_a11y_events_based_on_state"
+ namespace: "accessibility"
+ description: "Sends accessibility events in TouchExplorer#onAccessibilityEvent based on internal state to keep it consistent. This reduces test flakiness."
+ bug: "295575684"
+}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 898cdcc..b696998 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -136,6 +136,7 @@
":display-device-config",
":display-layout-config",
":device-state-config",
+ ":framework-core-nfc-infcadapter-sources",
"java/com/android/server/EventLogTags.logtags",
"java/com/android/server/am/EventLogTags.logtags",
"java/com/android/server/wm/EventLogTags.logtags",
@@ -195,6 +196,7 @@
"android.hardware.rebootescrow-V1-java",
"android.hardware.power.stats-V2-java",
"android.hidl.manager-V1.2-java",
+ "android.nfc.flags-aconfig-java",
"cbor-java",
"icu4j_calendar_astronomer",
"android.security.aaid_aidl-java",
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index beea063..8624dd5 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1236,7 +1236,7 @@
private void onUserStopped(int userId) {
Slog.d(TAG, "onUserStopped " + userId);
- Watchdog.getInstance().setOneOffTimeoutForMonitors(
+ Watchdog.getInstance().pauseWatchingMonitorsFor(
SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#onUserStopped might be slow");
try {
mVold.onUserStopped(userId);
@@ -1320,7 +1320,7 @@
unlockedUsers.add(userId);
}
}
- Watchdog.getInstance().setOneOffTimeoutForMonitors(
+ Watchdog.getInstance().pauseWatchingMonitorsFor(
SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#onUserStopped might be slow");
for (Integer userId : unlockedUsers) {
try {
@@ -2341,7 +2341,7 @@
try {
// TODO(b/135341433): Remove cautious logging when FUSE is stable
Slog.i(TAG, "Mounting volume " + vol);
- Watchdog.getInstance().setOneOffTimeoutForMonitors(
+ Watchdog.getInstance().pauseWatchingMonitorsFor(
SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#mount might be slow");
mVold.mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub() {
@Override
@@ -2472,7 +2472,7 @@
final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
- Watchdog.getInstance().setOneOffTimeoutForMonitors(
+ Watchdog.getInstance().pauseWatchingMonitorsFor(
PARTITION_OPERATION_WATCHDOG_TIMEOUT_MS, "#partition might be very slow");
try {
mVold.partition(diskId, IVold.PARTITION_TYPE_PUBLIC, -1);
@@ -2491,7 +2491,7 @@
final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
- Watchdog.getInstance().setOneOffTimeoutForMonitors(
+ Watchdog.getInstance().pauseWatchingMonitorsFor(
PARTITION_OPERATION_WATCHDOG_TIMEOUT_MS, "#partition might be very slow");
try {
mVold.partition(diskId, IVold.PARTITION_TYPE_PRIVATE, -1);
@@ -2510,7 +2510,7 @@
final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
- Watchdog.getInstance().setOneOffTimeoutForMonitors(
+ Watchdog.getInstance().pauseWatchingMonitorsFor(
PARTITION_OPERATION_WATCHDOG_TIMEOUT_MS, "#partition might be very slow");
try {
mVold.partition(diskId, IVold.PARTITION_TYPE_MIXED, ratio);
@@ -3620,7 +3620,7 @@
@Override
public ParcelFileDescriptor open() throws AppFuseMountException {
- Watchdog.getInstance().setOneOffTimeoutForMonitors(
+ Watchdog.getInstance().pauseWatchingMonitorsFor(
SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#open might be slow");
try {
final FileDescriptor fd = mVold.mountAppFuse(uid, mountId);
@@ -3634,7 +3634,7 @@
@Override
public ParcelFileDescriptor openFile(int mountId, int fileId, int flags)
throws AppFuseMountException {
- Watchdog.getInstance().setOneOffTimeoutForMonitors(
+ Watchdog.getInstance().pauseWatchingMonitorsFor(
SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#openFile might be slow");
try {
return new ParcelFileDescriptor(
@@ -3646,7 +3646,7 @@
@Override
public void close() throws Exception {
- Watchdog.getInstance().setOneOffTimeoutForMonitors(
+ Watchdog.getInstance().pauseWatchingMonitorsFor(
SLOW_OPERATION_WATCHDOG_TIMEOUT_MS, "#close might be slow");
if (mMounted) {
mVold.unmountAppFuse(uid, mountId);
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 55aa716..003046a 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -250,7 +250,7 @@
private Monitor mCurrentMonitor;
private long mStartTimeMillis;
private int mPauseCount;
- private long mOneOffTimeoutMillis;
+ private long mPauseEndTimeMillis;
HandlerChecker(Handler handler, String name) {
mHandler = handler;
@@ -270,20 +270,19 @@
* @param handlerCheckerTimeoutMillis the timeout to use for this run
*/
public void scheduleCheckLocked(long handlerCheckerTimeoutMillis) {
- if (mOneOffTimeoutMillis > 0) {
- mWaitMaxMillis = mOneOffTimeoutMillis;
- mOneOffTimeoutMillis = 0;
- } else {
- mWaitMaxMillis = handlerCheckerTimeoutMillis;
- }
+ mWaitMaxMillis = handlerCheckerTimeoutMillis;
if (mCompleted) {
// Safe to update monitors in queue, Handler is not in the middle of work
mMonitors.addAll(mMonitorQueue);
mMonitorQueue.clear();
}
+
+ long nowMillis = SystemClock.uptimeMillis();
+ boolean isPaused = mPauseCount > 0
+ || (mPauseEndTimeMillis > 0 && mPauseEndTimeMillis < nowMillis);
if ((mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling())
- || (mPauseCount > 0)) {
+ || isPaused) {
// Don't schedule until after resume OR
// If the target looper has recently been polling, then
// there is no reason to enqueue our checker on it since that
@@ -301,7 +300,8 @@
mCompleted = false;
mCurrentMonitor = null;
- mStartTimeMillis = SystemClock.uptimeMillis();
+ mStartTimeMillis = nowMillis;
+ mPauseEndTimeMillis = 0;
mHandler.postAtFrontOfQueue(this);
}
@@ -360,20 +360,19 @@
}
/**
- * Sets the timeout of the HandlerChecker for one run.
+ * Pauses the checks for the given time.
*
- * <p>The current run will be ignored and the next run will be set to this timeout.
- *
- * <p>If a one off timeout is already set, the maximum timeout will be used.
+ * <p>The current run will be ignored and another run will be scheduled after
+ * the given time.
*/
- public void setOneOffTimeoutLocked(int temporaryTimeoutMillis, String reason) {
- mOneOffTimeoutMillis = Math.max(temporaryTimeoutMillis, mOneOffTimeoutMillis);
+ public void pauseForLocked(int pauseMillis, String reason) {
+ mPauseEndTimeMillis = SystemClock.uptimeMillis() + pauseMillis;
// Mark as completed, because there's a chance we called this after the watchog
// thread loop called Object#wait after 'WAITED_HALF'. In that case we want to ensure
// the next call to #getCompletionStateLocked for this checker returns 'COMPLETED'
mCompleted = true;
- Slog.i(TAG, "Extending timeout of HandlerChecker: " + mName + " for reason: "
- + reason + ". New timeout: " + mOneOffTimeoutMillis);
+ Slog.i(TAG, "Pausing of HandlerChecker: " + mName + " for reason: "
+ + reason + ". Pause end time: " + mPauseEndTimeMillis);
}
/** Pause the HandlerChecker. */
@@ -623,34 +622,32 @@
}
/**
- * Sets a one-off timeout for the next run of the watchdog for this thread. This is useful
+ * Pauses the checks of the watchdog for this thread. This is useful
* to run a slow operation on one of the monitored thread.
*
- * <p>After the next run, the timeout will go back to the default value.
- *
- * <p>If the current thread has not been added to the Watchdog, this call is a no-op.
- *
- * <p>If a one-off timeout for the current thread is already, the max value will be used.
+ * <p>After the given time, the timeout will go back to the default value.
+ * <p>This method does not require resume to be called.
*/
- public void setOneOffTimeoutForCurrentThread(int oneOffTimeoutMillis, String reason) {
+ public void pauseWatchingCurrentThreadFor(int pauseMillis, String reason) {
synchronized (mLock) {
for (HandlerCheckerAndTimeout hc : mHandlerCheckers) {
HandlerChecker checker = hc.checker();
if (Thread.currentThread().equals(checker.getThread())) {
- checker.setOneOffTimeoutLocked(oneOffTimeoutMillis, reason);
+ checker.pauseForLocked(pauseMillis, reason);
}
}
}
}
/**
- * Sets a one-off timeout for the next run of the watchdog for the monitor thread.
+ * Pauses the checks of the watchdog for the monitor thread for the given time
*
- * <p>Simiar to {@link setOneOffTimeoutForCurrentThread} but used for monitors added through
- * {@link #addMonitor}
+ * <p>Similar to {@link pauseWatchingCurrentThreadFor} but used for monitors added
+ * through {@link #addMonitor}
+ * <p>This method does not require resume to be called.
*/
- public void setOneOffTimeoutForMonitors(int oneOffTimeoutMillis, String reason) {
- mMonitorChecker.setOneOffTimeoutLocked(oneOffTimeoutMillis, reason);
+ public void pauseWatchingMonitorsFor(int pauseMillis, String reason) {
+ mMonitorChecker.pauseForLocked(pauseMillis, reason);
}
/**
@@ -664,7 +661,7 @@
* adds another pause and will require an additional {@link #resumeCurrentThread} to resume.
*
* <p>Note: Use with care, as any deadlocks on the current thread will be undetected until all
- * pauses have been resumed. Prefer to use #setOneOffTimeoutForCurrentThread.
+ * pauses have been resumed. Prefer to use #pauseWatchingCurrentThreadFor.
*/
public void pauseWatchingCurrentThread(String reason) {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
index 9b5f18c..710278d 100644
--- a/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
+++ b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+
import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
@@ -54,6 +56,7 @@
setButton(DialogInterface.BUTTON_POSITIVE, "Force Close", mHandler.obtainMessage(1, app));
setTitle("Waiting For Debugger");
WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.privateFlags |= SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
attrs.setTitle("Waiting For Debugger: " + app.info.processName);
getWindow().setAttributes(attrs);
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index e0e6cad..59d8e7e 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -869,6 +869,8 @@
ApplicationExitInfo.REASON_LOW_MEMORY,
ApplicationExitInfo.SUBREASON_OOM_KILL,
"oom");
+
+ oomKill.logKillOccurred();
}
}
}
diff --git a/services/core/java/com/android/server/audio/AdiDeviceState.java b/services/core/java/com/android/server/audio/AdiDeviceState.java
index ba43c8d..292fc14 100644
--- a/services/core/java/com/android/server/audio/AdiDeviceState.java
+++ b/services/core/java/com/android/server/audio/AdiDeviceState.java
@@ -188,7 +188,7 @@
* {@link AdiDeviceState#toPersistableString()}.
*/
public static int getPeristedMaxSize() {
- return 36; /* (mDeviceType)2 + (mDeviceAddresss)17 + (mInternalDeviceType)9 + (mSAEnabled)1
+ return 36; /* (mDeviceType)2 + (mDeviceAddress)17 + (mInternalDeviceType)9 + (mSAEnabled)1
+ (mHasHeadTracker)1 + (mHasHeadTrackerEnabled)1
+ (SETTINGS_FIELD_SEPARATOR)5 */
}
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 3d347be..f9bc8dc 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -53,6 +53,8 @@
import android.hardware.usb.UsbManager;
import android.media.AudioManager;
import android.nfc.INfcAdapter;
+import android.nfc.NfcAdapter;
+import android.nfc.NfcManager;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerExecutor;
@@ -163,10 +165,6 @@
* SCALER_ROTATE_AND_CROP_NONE -> Always return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE
*/
- // Flags arguments to NFC adapter to enable/disable NFC
- public static final int DISABLE_POLLING_FLAGS = 0x1000;
- public static final int ENABLE_POLLING_FLAGS = 0x0000;
-
// Handler message codes
private static final int MSG_SWITCH_USER = 1;
private static final int MSG_NOTIFY_DEVICE_STATE = 2;
@@ -216,7 +214,6 @@
private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>();
private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc";
- private static final String NFC_SERVICE_BINDER_NAME = "nfc";
private static final IBinder nfcInterfaceToken = new Binder();
private final boolean mNotifyNfc;
@@ -1274,8 +1271,13 @@
}
}
- private void notifyNfcService(boolean enablePolling) {
-
+ // TODO(b/303286040): Remove the raw INfcAdapter usage once |ENABLE_NFC_MAINLINE_FLAG| is
+ // rolled out.
+ private static final String NFC_SERVICE_BINDER_NAME = "nfc";
+ // Flags arguments to NFC adapter to enable/disable NFC
+ public static final int DISABLE_POLLING_FLAGS = 0x1000;
+ public static final int ENABLE_POLLING_FLAGS = 0x0000;
+ private void setNfcReaderModeUsingINfcAdapter(boolean enablePolling) {
IBinder nfcServiceBinder = getBinderService(NFC_SERVICE_BINDER_NAME);
if (nfcServiceBinder == null) {
Slog.w(TAG, "Could not connect to NFC service to notify it of camera state");
@@ -1291,6 +1293,25 @@
}
}
+ private void notifyNfcService(boolean enablePolling) {
+ if (android.nfc.Flags.enableNfcMainline()) {
+ NfcManager nfcManager = mContext.getSystemService(NfcManager.class);
+ if (nfcManager == null) {
+ Slog.w(TAG, "Could not connect to NFC service to notify it of camera state");
+ return;
+ }
+ NfcAdapter nfcAdapter = nfcManager.getDefaultAdapter();
+ if (nfcAdapter == null) {
+ Slog.w(TAG, "Could not connect to NFC service to notify it of camera state");
+ return;
+ }
+ if (DEBUG) Slog.v(TAG, "Setting NFC reader mode. enablePolling: " + enablePolling);
+ nfcAdapter.setReaderMode(enablePolling);
+ } else {
+ setNfcReaderModeUsingINfcAdapter(enablePolling);
+ }
+ }
+
private static int[] toArray(Collection<Integer> c) {
int len = c.size();
int[] ret = new int[len];
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index a788968..e5f01df 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2307,8 +2307,10 @@
@GuardedBy("mSyncRoot")
private boolean hdrConversionIntroducesLatencyLocked() {
+ HdrConversionMode mode = getHdrConversionModeSettingInternal();
final int preferredHdrOutputType =
- getHdrConversionModeSettingInternal().getPreferredHdrOutputType();
+ mode.getConversionMode() == HdrConversionMode.HDR_CONVERSION_SYSTEM
+ ? mSystemPreferredHdrOutputType : mode.getPreferredHdrOutputType();
if (preferredHdrOutputType != Display.HdrCapabilities.HDR_TYPE_INVALID) {
int[] hdrTypesWithLatency = mInjector.getHdrOutputTypesWithLatency();
return ArrayUtils.contains(hdrTypesWithLatency, preferredHdrOutputType);
@@ -2589,16 +2591,14 @@
// TODO(b/202378408) set minimal post-processing only if it's supported once we have a
// separate API for disabling on-device processing.
boolean mppRequest = isMinimalPostProcessingAllowed() && preferMinimalPostProcessing;
- boolean disableHdrConversionForLatency = false;
+ // If HDR conversion introduces latency, disable that in case minimal
+ // post-processing is requested
+ boolean disableHdrConversionForLatency =
+ mppRequest ? hdrConversionIntroducesLatencyLocked() : false;
if (display.getRequestedMinimalPostProcessingLocked() != mppRequest) {
display.setRequestedMinimalPostProcessingLocked(mppRequest);
shouldScheduleTraversal = true;
- // If HDR conversion introduces latency, disable that in case minimal
- // post-processing is requested
- if (mppRequest) {
- disableHdrConversionForLatency = hdrConversionIntroducesLatencyLocked();
- }
}
if (shouldScheduleTraversal) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
index d97c8e7..8c39d7d 100644
--- a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
+++ b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
@@ -16,6 +16,13 @@
package com.android.server.display;
+import static android.view.Display.TYPE_EXTERNAL;
+import static android.view.Display.TYPE_INTERNAL;
+import static android.view.Display.TYPE_OVERLAY;
+import static android.view.Display.TYPE_UNKNOWN;
+import static android.view.Display.TYPE_VIRTUAL;
+import static android.view.Display.TYPE_WIFI;
+
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManager;
@@ -26,7 +33,10 @@
import com.android.server.display.feature.DisplayManagerFlags;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
class DisplayManagerShellCommand extends ShellCommand {
private static final String TAG = "DisplayManagerShellCommand";
@@ -153,9 +163,12 @@
pw.println(" Sets the user disabled HDR types as TYPES");
pw.println(" get-user-disabled-hdr-types");
pw.println(" Returns the user disabled HDR types");
- pw.println(" get-displays [CATEGORY]");
+ pw.println(" get-displays [-c|--category CATEGORY] [-i|--ids-only] [-t|--type TYPE]");
+ pw.println(" [CATEGORY]");
pw.println(" Returns the current displays. Can specify string category among");
pw.println(" DisplayManager.DISPLAY_CATEGORY_*; must use the actual string value.");
+ pw.println(" Can choose to print only the ids of the displays. " + "Can filter by");
+ pw.println(" display types. For example, '--type external'");
pw.println(" dock");
pw.println(" Sets brightness to docked + idle screen brightness mode");
pw.println(" undock");
@@ -171,17 +184,94 @@
}
private int getDisplays() {
- String category = getNextArg();
+ String opt = "", requestedType, category = null;
+ PrintWriter out = getOutPrintWriter();
+
+ List<Integer> displayTypeList = new ArrayList<>();
+ boolean showIdsOnly = false, filterByType = false;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "-i":
+ case "--ids-only":
+ showIdsOnly = true;
+ break;
+ case "-t":
+ case "--type":
+ requestedType = getNextArgRequired();
+ int displayType = getType(requestedType, out);
+ if (displayType == -1) {
+ return 1;
+ }
+ displayTypeList.add(displayType);
+ filterByType = true;
+ break;
+ case "-c":
+ case "--category":
+ if (category != null) {
+ out.println("Error: the category has been specified more than one time. "
+ + "Please select only one category.");
+ return 1;
+ }
+ category = getNextArgRequired();
+ break;
+ case "":
+ break;
+ default:
+ out.println("Error: unknown option '" + opt + "'");
+ return 1;
+ }
+ }
+
+ String lastCategoryArgument = getNextArg();
+ if (lastCategoryArgument != null) {
+ if (category != null) {
+ out.println("Error: the category has been specified both with the -c option and "
+ + "the positional argument. Please select only one category.");
+ return 1;
+ }
+ category = lastCategoryArgument;
+ }
+
DisplayManager dm = mService.getContext().getSystemService(DisplayManager.class);
Display[] displays = dm.getDisplays(category);
- PrintWriter out = getOutPrintWriter();
- out.println("Displays:");
+
+ if (filterByType) {
+ displays = Arrays.stream(displays).filter(d -> displayTypeList.contains(d.getType()))
+ .toArray(Display[]::new);
+ }
+
+ if (!showIdsOnly) {
+ out.println("Displays:");
+ }
for (int i = 0; i < displays.length; i++) {
- out.println(" " + displays[i]);
+ out.println((showIdsOnly ? displays[i].getDisplayId() : displays[i]));
}
return 0;
}
+ private int getType(String type, PrintWriter out) {
+ type = type.toUpperCase(Locale.ENGLISH);
+ switch (type) {
+ case "UNKNOWN":
+ return TYPE_UNKNOWN;
+ case "INTERNAL":
+ return TYPE_INTERNAL;
+ case "EXTERNAL":
+ return TYPE_EXTERNAL;
+ case "WIFI":
+ return TYPE_WIFI;
+ case "OVERLAY":
+ return TYPE_OVERLAY;
+ case "VIRTUAL":
+ return TYPE_VIRTUAL;
+ default:
+ out.println("Error: argument for display type should be "
+ + "one of 'UNKNOWN', 'INTERNAL', 'EXTERNAL', 'WIFI', 'OVERLAY', 'VIRTUAL', "
+ + "but got '" + type + "' instead.");
+ return -1;
+ }
+ }
+
private int showNotification() {
final String notificationType = getNextArg();
if (notificationType == null) {
diff --git a/services/core/java/com/android/server/media/AudioAttributesUtils.java b/services/core/java/com/android/server/media/AudioAttributesUtils.java
index 5d5d59b..8cb334d 100644
--- a/services/core/java/com/android/server/media/AudioAttributesUtils.java
+++ b/services/core/java/com/android/server/media/AudioAttributesUtils.java
@@ -23,6 +23,8 @@
import android.media.AudioDeviceInfo;
import android.media.MediaRoute2Info;
+import com.android.media.flags.Flags;
+
/* package */ final class AudioAttributesUtils {
/* package */ static final AudioAttributes ATTRIBUTES_MEDIA = new AudioAttributes.Builder()
@@ -36,6 +38,14 @@
@MediaRoute2Info.Type
/* package */ static int mapToMediaRouteType(
@NonNull AudioDeviceAttributes audioDeviceAttributes) {
+ if (Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
+ switch (audioDeviceAttributes.getType()) {
+ case AudioDeviceInfo.TYPE_HDMI_ARC:
+ return MediaRoute2Info.TYPE_HDMI_ARC;
+ case AudioDeviceInfo.TYPE_HDMI_EARC:
+ return MediaRoute2Info.TYPE_HDMI_EARC;
+ }
+ }
switch (audioDeviceAttributes.getType()) {
case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE:
case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
@@ -64,7 +74,6 @@
}
}
-
/* package */ static boolean isDeviceOutputAttributes(
@Nullable AudioDeviceAttributes audioDeviceAttributes) {
if (audioDeviceAttributes == null) {
diff --git a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
index 33190ad..360a6a7 100644
--- a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
+++ b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java
@@ -22,6 +22,8 @@
import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_DOCK;
import static android.media.MediaRoute2Info.TYPE_HDMI;
+import static android.media.MediaRoute2Info.TYPE_HDMI_ARC;
+import static android.media.MediaRoute2Info.TYPE_HDMI_EARC;
import static android.media.MediaRoute2Info.TYPE_USB_DEVICE;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
@@ -160,7 +162,6 @@
@NonNull
private MediaRoute2Info createRouteFromAudioInfo(@MediaRoute2Info.Type int type) {
int name = R.string.default_audio_route_name;
-
switch (type) {
case TYPE_WIRED_HEADPHONES:
case TYPE_WIRED_HEADSET:
@@ -170,6 +171,8 @@
name = R.string.default_audio_route_name_dock_speakers;
break;
case TYPE_HDMI:
+ case TYPE_HDMI_ARC:
+ case TYPE_HDMI_EARC:
name = R.string.default_audio_route_name_external_device;
break;
case TYPE_USB_DEVICE:
@@ -211,6 +214,8 @@
case TYPE_WIRED_HEADSET:
case TYPE_DOCK:
case TYPE_HDMI:
+ case TYPE_HDMI_ARC:
+ case TYPE_HDMI_EARC:
case TYPE_USB_DEVICE:
return true;
default:
diff --git a/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java
new file mode 100644
index 0000000..5bad067
--- /dev/null
+++ b/services/core/java/com/android/server/media/projection/FrameworkStatsLogWrapper.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media.projection;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+/** Wrapper around {@link FrameworkStatsLog} */
+public class FrameworkStatsLogWrapper {
+
+ /** Wrapper around {@link FrameworkStatsLog#write}. */
+ public void write(
+ int code,
+ int sessionId,
+ int state,
+ int previousState,
+ int hostUid,
+ int targetUid,
+ int timeSinceLastActive,
+ int creationSource) {
+ FrameworkStatsLog.write(
+ code,
+ sessionId,
+ state,
+ previousState,
+ hostUid,
+ targetUid,
+ timeSinceLastActive,
+ creationSource);
+ }
+}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 8cbc368..ce35a61 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -162,7 +162,7 @@
mWmInternal = LocalServices.getService(WindowManagerInternal.class);
mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
mMediaRouterCallback = new MediaRouterCallback();
- mMediaProjectionMetricsLogger = injector.mediaProjectionMetricsLogger();
+ mMediaProjectionMetricsLogger = injector.mediaProjectionMetricsLogger(context);
Watchdog.getInstance().addMonitor(this);
}
@@ -197,8 +197,8 @@
return Looper.getMainLooper();
}
- MediaProjectionMetricsLogger mediaProjectionMetricsLogger() {
- return MediaProjectionMetricsLogger.getInstance();
+ MediaProjectionMetricsLogger mediaProjectionMetricsLogger(Context context) {
+ return MediaProjectionMetricsLogger.getInstance(context);
}
}
@@ -293,6 +293,12 @@
private void stopProjectionLocked(final MediaProjection projection) {
Slog.d(TAG, "Content Recording: Stopped active MediaProjection and "
+ "dispatching stop to callbacks");
+ ContentRecordingSession session = projection.mSession;
+ int targetUid =
+ session != null
+ ? session.getTargetUid()
+ : ContentRecordingSession.TARGET_UID_UNKNOWN;
+ mMediaProjectionMetricsLogger.logStopped(projection.uid, targetUid);
mProjectionToken = null;
mProjectionGrant = null;
dispatchStop(projection);
@@ -452,6 +458,11 @@
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
}
+ @VisibleForTesting
+ void notifyPermissionRequestInitiated(int hostUid, int sessionCreationSource) {
+ mMediaProjectionMetricsLogger.logInitiated(hostUid, sessionCreationSource);
+ }
+
/**
* Handles result of dialog shown from
* {@link BinderService#buildReviewGrantedConsentIntentLocked()}.
@@ -842,6 +853,19 @@
}
@Override // Binder call
+ @EnforcePermission(MANAGE_MEDIA_PROJECTION)
+ public void notifyPermissionRequestInitiated(int hostUid, int sessionCreationSource) {
+ notifyPermissionRequestInitiated_enforcePermission();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ MediaProjectionManagerService.this.notifyPermissionRequestInitiated(
+ hostUid, sessionCreationSource);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
index f18ecad..c8b932a 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
@@ -16,35 +16,127 @@
package com.android.server.media.projection;
+import android.content.Context;
import com.android.internal.util.FrameworkStatsLog;
-/**
- * Class for emitting logs describing a MediaProjection session.
- */
+import java.time.Duration;
+
+/** Class for emitting logs describing a MediaProjection session. */
public class MediaProjectionMetricsLogger {
+ private static final int TARGET_UID_UNKNOWN = -2;
+ private static final int TIME_SINCE_LAST_ACTIVE_UNKNOWN = -1;
+
private static MediaProjectionMetricsLogger sSingleton = null;
- public static MediaProjectionMetricsLogger getInstance() {
+ private final FrameworkStatsLogWrapper mFrameworkStatsLogWrapper;
+ private final MediaProjectionSessionIdGenerator mSessionIdGenerator;
+ private final MediaProjectionTimestampStore mTimestampStore;
+
+ private int mPreviousState =
+ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
+
+ MediaProjectionMetricsLogger(
+ FrameworkStatsLogWrapper frameworkStatsLogWrapper,
+ MediaProjectionSessionIdGenerator sessionIdGenerator,
+ MediaProjectionTimestampStore timestampStore) {
+ mFrameworkStatsLogWrapper = frameworkStatsLogWrapper;
+ mSessionIdGenerator = sessionIdGenerator;
+ mTimestampStore = timestampStore;
+ }
+
+ /** Returns a singleton instance of {@link MediaProjectionMetricsLogger}. */
+ public static MediaProjectionMetricsLogger getInstance(Context context) {
if (sSingleton == null) {
- sSingleton = new MediaProjectionMetricsLogger();
+ sSingleton =
+ new MediaProjectionMetricsLogger(
+ new FrameworkStatsLogWrapper(),
+ MediaProjectionSessionIdGenerator.getInstance(context),
+ MediaProjectionTimestampStore.getInstance(context));
}
return sSingleton;
}
- void notifyProjectionStateChange(int hostUid, int state, int sessionCreationSource) {
+ /**
+ * Logs that the media projection session was initiated by the app requesting the user's consent
+ * to capture. Should be sent even if the permission dialog is not shown.
+ *
+ * @param hostUid UID of the package that initiates MediaProjection.
+ * @param sessionCreationSource Where this session started. One of:
+ * <ul>
+ * <li>{@link
+ * FrameworkStatsLog#MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_APP}
+ * <li>{@link
+ * FrameworkStatsLog#MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_CAST}
+ * <li>{@link
+ * FrameworkStatsLog#MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_SYSTEM_UI_SCREEN_RECORDER}
+ * <li>{@link
+ * FrameworkStatsLog#MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN}
+ * </ul>
+ */
+ public void logInitiated(int hostUid, int sessionCreationSource) {
+ Duration durationSinceLastActiveSession = mTimestampStore.timeSinceLastActiveSession();
+ int timeSinceLastActiveInSeconds =
+ durationSinceLastActiveSession == null
+ ? TIME_SINCE_LAST_ACTIVE_UNKNOWN
+ : (int) durationSinceLastActiveSession.toSeconds();
+ write(
+ mSessionIdGenerator.createAndGetNewSessionId(),
+ FrameworkStatsLog
+ .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED,
+ hostUid,
+ TARGET_UID_UNKNOWN,
+ timeSinceLastActiveInSeconds,
+ sessionCreationSource);
+ }
+
+ /** Logs that the capturing stopped, either normally or because of error. */
+ public void logStopped(int hostUid, int targetUid) {
+ write(
+ mSessionIdGenerator.getCurrentSessionId(),
+ FrameworkStatsLog
+ .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED,
+ hostUid,
+ targetUid,
+ TIME_SINCE_LAST_ACTIVE_UNKNOWN,
+ FrameworkStatsLog
+ .MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ mTimestampStore.registerActiveSessionEnded();
+ }
+
+ public void notifyProjectionStateChange(int hostUid, int state, int sessionCreationSource) {
write(hostUid, state, sessionCreationSource);
}
private void write(int hostUid, int state, int sessionCreationSource) {
- FrameworkStatsLog.write(
+ mFrameworkStatsLogWrapper.write(
/* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
/* session_id */ 123,
/* state */ state,
- /* previous_state */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN,
+ /* previous_state */ FrameworkStatsLog
+ .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN,
/* host_uid */ hostUid,
/* target_uid */ -1,
/* time_since_last_active */ 0,
/* creation_source */ sessionCreationSource);
}
+
+ private void write(
+ int sessionId,
+ int state,
+ int hostUid,
+ int targetUid,
+ int timeSinceLastActive,
+ int creationSource) {
+ mFrameworkStatsLogWrapper.write(
+ /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
+ sessionId,
+ state,
+ mPreviousState,
+ hostUid,
+ targetUid,
+ timeSinceLastActive,
+ creationSource);
+ mPreviousState = state;
+ }
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionSessionIdGenerator.java b/services/core/java/com/android/server/media/projection/MediaProjectionSessionIdGenerator.java
index ff70cb3..244de0b 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionSessionIdGenerator.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionSessionIdGenerator.java
@@ -47,8 +47,11 @@
if (sInstance == null) {
File preferencesFile =
new File(Environment.getDataSystemDirectory(), PREFERENCES_FILE_NAME);
+ // Needed as this class is instantiated before the device is unlocked.
+ Context directBootContext = context.createDeviceProtectedStorageContext();
SharedPreferences preferences =
- context.getSharedPreferences(preferencesFile, Context.MODE_PRIVATE);
+ directBootContext.getSharedPreferences(
+ preferencesFile, Context.MODE_PRIVATE);
sInstance = new MediaProjectionSessionIdGenerator(preferences);
}
return sInstance;
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionTimestampStore.java b/services/core/java/com/android/server/media/projection/MediaProjectionTimestampStore.java
index 4026d0c..bfec58c 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionTimestampStore.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionTimestampStore.java
@@ -59,8 +59,11 @@
if (sInstance == null) {
File preferencesFile =
new File(Environment.getDataSystemDirectory(), PREFERENCES_FILE_NAME);
+ // Needed as this class is instantiated before the device is unlocked.
+ Context directBootContext = context.createDeviceProtectedStorageContext();
SharedPreferences preferences =
- context.getSharedPreferences(preferencesFile, Context.MODE_PRIVATE);
+ directBootContext.getSharedPreferences(
+ preferencesFile, Context.MODE_PRIVATE);
sInstance = new MediaProjectionTimestampStore(preferences, InstantSource.system());
}
return sInstance;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b4d36db..7ca5699 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -71,6 +71,7 @@
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+import static android.os.Flags.allowPrivateProfile;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
@@ -289,7 +290,6 @@
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.MetricsLogger;
@@ -1179,7 +1179,7 @@
@Override
public void onSetDisabled(int status) {
synchronized (mNotificationLock) {
- if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mAttentionHelper.updateDisableNotificationEffectsLocked(status);
} else {
mDisableNotificationEffects =
@@ -1325,7 +1325,7 @@
public void clearEffects() {
synchronized (mNotificationLock) {
if (DBG) Slog.d(TAG, "clearEffects");
- if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mAttentionHelper.clearAttentionEffects();
} else {
clearSoundLocked();
@@ -1554,8 +1554,7 @@
int changedFlags = data.getFlags() ^ flags;
if ((changedFlags & FLAG_SUPPRESS_NOTIFICATION) != 0) {
// Suppress notification flag changed, clear any effects
- if (mFlagResolver.isEnabled(
- NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mAttentionHelper.clearEffectsLocked(key);
} else {
clearEffectsLocked(key);
@@ -1904,7 +1903,7 @@
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (!mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (!Flags.refactorAttentionHelper()) {
if (action.equals(Intent.ACTION_SCREEN_ON)) {
// Keep track of screen on/off state, but do not turn off the notification light
// until user passes through the lock screen or views the notification.
@@ -1931,7 +1930,8 @@
cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle,
REASON_USER_STOPPED);
}
- } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
+ } else if (
+ isProfileUnavailable(action)) {
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userHandle >= 0 && !mDpm.isKeepProfilesRunningEnabled()) {
cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle,
@@ -1982,6 +1982,12 @@
}
}
}
+
+ private boolean isProfileUnavailable(String action) {
+ return allowPrivateProfile() ?
+ action.equals(Intent.ACTION_PROFILE_UNAVAILABLE) :
+ action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ }
};
private final class SettingsObserver extends ContentObserver {
@@ -2011,7 +2017,7 @@
ContentResolver resolver = getContext().getContentResolver();
resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
false, this, UserHandle.USER_ALL);
- if (!mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (!Flags.refactorAttentionHelper()) {
resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
false, this, UserHandle.USER_ALL);
}
@@ -2037,7 +2043,7 @@
public void update(Uri uri) {
ContentResolver resolver = getContext().getContentResolver();
- if (!mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (!Flags.refactorAttentionHelper()) {
if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
boolean pulseEnabled = Settings.System.getIntForUser(resolver,
Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
@@ -2530,7 +2536,7 @@
mToastRateLimiter = toastRateLimiter;
- if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mAttentionHelper = new NotificationAttentionHelper(getContext(), lightsManager,
mAccessibilityManager, mPackageManagerClient, userManager, usageStats,
mNotificationManagerPrivate, mZenModeHelper, flagResolver);
@@ -2540,7 +2546,7 @@
// If this is called within a test, make sure to unregister the intent receivers by
// calling onDestroy()
IntentFilter filter = new IntentFilter();
- if (!mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (!Flags.refactorAttentionHelper()) {
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
@@ -2552,6 +2558,9 @@
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ if (allowPrivateProfile()){
+ filter.addAction(Intent.ACTION_PROFILE_UNAVAILABLE);
+ }
getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
IntentFilter pkgFilter = new IntentFilter();
@@ -2865,7 +2874,7 @@
}
registerNotificationPreferencesPullers();
new LockPatternUtils(getContext()).registerStrongAuthTracker(mStrongAuthTracker);
- if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mAttentionHelper.onSystemReady();
}
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
@@ -6490,7 +6499,7 @@
pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
pw.println(" hideSilentStatusBar="
+ mPreferencesHelper.shouldHideSilentStatusIcons());
- if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mAttentionHelper.dump(pw, " ", filter);
}
}
@@ -7756,7 +7765,7 @@
boolean wasPosted = removeFromNotificationListsLocked(r);
cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null,
SystemClock.elapsedRealtime());
- if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mAttentionHelper.updateLightsLocked();
} else {
updateLightsLocked();
@@ -7889,7 +7898,7 @@
cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
mSendDelete, childrenFlagChecker, mReason,
mCancellationElapsedTimeMs);
- if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mAttentionHelper.updateLightsLocked();
} else {
updateLightsLocked();
@@ -8186,7 +8195,7 @@
int buzzBeepBlinkLoggingCode = 0;
if (!r.isHidden()) {
- if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
buzzBeepBlinkLoggingCode = mAttentionHelper.buzzBeepBlinkLocked(r,
new NotificationAttentionHelper.Signals(
mUserProfiles.isCurrentProfile(r.getUserId()),
@@ -9173,7 +9182,7 @@
|| interruptiveChanged;
if (interceptBefore && !record.isIntercepted()
&& record.isNewEnoughForAlerting(System.currentTimeMillis())) {
- if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mAttentionHelper.buzzBeepBlinkLocked(record,
new NotificationAttentionHelper.Signals(
mUserProfiles.isCurrentProfile(record.getUserId()), mListenerHints));
@@ -9553,7 +9562,7 @@
});
}
- if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mAttentionHelper.clearEffectsLocked(canceledKey);
} else {
// sound
@@ -9917,7 +9926,7 @@
cancellationElapsedTimeMs);
}
}
- if (mFlagResolver.isEnabled(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mAttentionHelper.updateLightsLocked();
} else {
updateLightsLocked();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 3a6664a..7c0fc99 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -139,6 +139,7 @@
import android.os.FactoryTest;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeReason;
@@ -715,6 +716,11 @@
private static final int MSG_LOG_KEYBOARD_SYSTEM_EVENT = 26;
private class PolicyHandler extends Handler {
+
+ private PolicyHandler(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -2166,10 +2172,12 @@
static class Injector {
private final Context mContext;
private final WindowManagerFuncs mWindowManagerFuncs;
+ private final Looper mLooper;
- Injector(Context context, WindowManagerFuncs funcs) {
+ Injector(Context context, WindowManagerFuncs funcs, Looper looper) {
mContext = context;
mWindowManagerFuncs = funcs;
+ mLooper = looper;
}
Context getContext() {
@@ -2180,6 +2188,10 @@
return mWindowManagerFuncs;
}
+ Looper getLooper() {
+ return mLooper;
+ }
+
AccessibilityShortcutController getAccessibilityShortcutController(
Context context, Handler handler, int initialUserId) {
return new AccessibilityShortcutController(context, handler, initialUserId);
@@ -2208,7 +2220,7 @@
/** {@inheritDoc} */
@Override
public void init(Context context, WindowManagerFuncs funcs) {
- init(new Injector(context, funcs));
+ init(new Injector(context, funcs, Looper.myLooper()));
}
@VisibleForTesting
@@ -2284,7 +2296,7 @@
mContext, minHorizontal, maxHorizontal, minVertical, maxVertical, maxRadius);
}
- mHandler = new PolicyHandler();
+ mHandler = new PolicyHandler(injector.getLooper());
mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mSettingsObserver.observe();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
index c54e3bd..5f8bbe5 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
@@ -29,7 +29,6 @@
import android.annotation.Nullable;
import android.app.WallpaperColors;
-import android.app.WallpaperManager;
import android.app.WallpaperManager.SetWallpaperFlags;
import android.app.backup.WallpaperBackupHelper;
import android.content.ComponentName;
@@ -38,7 +37,6 @@
import android.content.res.Resources;
import android.graphics.Color;
import android.os.FileUtils;
-import android.os.SystemProperties;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -77,8 +75,6 @@
private final WallpaperCropper mWallpaperCropper;
private final Context mContext;
- private final boolean mIsLockscreenLiveWallpaperEnabled;
-
WallpaperDataParser(Context context, WallpaperDisplayHelper wallpaperDisplayHelper,
WallpaperCropper wallpaperCropper) {
mContext = context;
@@ -86,8 +82,6 @@
mWallpaperCropper = wallpaperCropper;
mImageWallpaper = ComponentName.unflattenFromString(
context.getResources().getString(R.string.image_wallpaper_component));
- mIsLockscreenLiveWallpaperEnabled =
- SystemProperties.getBoolean("persist.wm.debug.lockscreen_live_wallpaper", true);
}
private JournaledFile makeJournaledFile(int userId) {
@@ -127,42 +121,26 @@
}
/**
- * TODO(b/197814683) adapt comment once flag is removed
- *
* Load the system wallpaper (and the lock wallpaper, if it exists) from disk
* @param userId the id of the user for which the wallpaper should be loaded
* @param keepDimensionHints if false, parse and set the
* {@link DisplayData} width and height for the specified userId
- * @param wallpaper the wallpaper object to reuse to do the modifications.
- * If null, a new object will be created.
- * @param lockWallpaper the lock wallpaper object to reuse to do the modifications.
- * If null, a new object will be created.
- * @param which The wallpaper(s) to load. Only has effect if
- * {@link WallpaperManager#isLockscreenLiveWallpaperEnabled} is true,
- * otherwise both wallpaper will always be loaded.
+ * @param migrateFromOld whether the current wallpaper is pre-N and needs migration
+ * @param which The wallpaper(s) to load.
* @return a {@link WallpaperLoadingResult} object containing the wallpaper data.
- * This object will contain the {@code wallpaper} and
- * {@code lockWallpaper} provided as parameters, if they are not null.
*/
public WallpaperLoadingResult loadSettingsLocked(int userId, boolean keepDimensionHints,
- WallpaperData wallpaper, WallpaperData lockWallpaper, @SetWallpaperFlags int which) {
+ boolean migrateFromOld, @SetWallpaperFlags int which) {
JournaledFile journal = makeJournaledFile(userId);
FileInputStream stream = null;
File file = journal.chooseForRead();
- boolean migrateFromOld = wallpaper == null;
+ boolean loadSystem = (which & FLAG_SYSTEM) != 0;
+ boolean loadLock = (which & FLAG_LOCK) != 0;
+ WallpaperData wallpaper = null;
+ WallpaperData lockWallpaper = null;
- boolean separateLockscreenEngine = mIsLockscreenLiveWallpaperEnabled;
- boolean loadSystem = !separateLockscreenEngine || (which & FLAG_SYSTEM) != 0;
- boolean loadLock = !separateLockscreenEngine || (which & FLAG_LOCK) != 0;
-
- // don't reuse the wallpaper objects in the new version
- if (separateLockscreenEngine) {
- wallpaper = null;
- lockWallpaper = null;
- }
-
- if (wallpaper == null && loadSystem) {
+ if (loadSystem) {
// Do this once per boot
if (migrateFromOld) migrateFromOld();
wallpaper = new WallpaperData(userId, FLAG_SYSTEM);
@@ -188,11 +166,8 @@
type = parser.next();
if (type == XmlPullParser.START_TAG) {
String tag = parser.getName();
- if (("wp".equals(tag) && loadSystem)
- || ("kwp".equals(tag) && mIsLockscreenLiveWallpaperEnabled
- && loadLock)) {
-
- if ("kwp".equals(tag) && lockWallpaper == null) {
+ if (("wp".equals(tag) && loadSystem) || ("kwp".equals(tag) && loadLock)) {
+ if ("kwp".equals(tag)) {
lockWallpaper = new WallpaperData(userId, FLAG_LOCK);
}
WallpaperData wallpaperToParse =
@@ -219,12 +194,6 @@
Slog.v(TAG, "mNextWallpaperComponent:"
+ wallpaper.nextWallpaperComponent);
}
- } else if ("kwp".equals(tag) && !mIsLockscreenLiveWallpaperEnabled) {
- // keyguard-specific wallpaper for this user (legacy code)
- if (lockWallpaper == null) {
- lockWallpaper = new WallpaperData(userId, FLAG_LOCK);
- }
- parseWallpaperAttributes(parser, lockWallpaper, false);
}
}
} while (type != XmlPullParser.END_DOCUMENT);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index c7a3c43..bdcde66 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -188,8 +188,6 @@
}
private final Object mLock = new Object();
- /** True to enable a second engine for lock screen wallpaper when different from system wp. */
- private final boolean mIsLockscreenLiveWallpaperEnabled;
/** True to support different crops for different display dimensions */
private final boolean mIsMultiCropEnabled;
/** Tracks wallpaper being migrated from system+lock to lock when setting static wp. */
@@ -230,7 +228,7 @@
mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG);
}
- WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) {
+ WallpaperData dataForEvent(boolean lockChanged) {
WallpaperData wallpaper = null;
synchronized (mLock) {
if (lockChanged) {
@@ -252,7 +250,7 @@
final File changedFile = new File(mWallpaperDir, path);
final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile));
final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile));
- final WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged);
+ final WallpaperData wallpaper = dataForEvent(lockWallpaperChanged);
final boolean moved = (event == MOVED_TO);
final boolean written = (event == CLOSE_WRITE || moved);
@@ -378,7 +376,7 @@
}
saveSettingsLocked(wallpaper.userId);
- if ((sysWallpaperChanged || lockWallpaperChanged) && localSync != null) {
+ if (localSync != null) {
localSync.complete();
}
}
@@ -389,129 +387,9 @@
}
}
- // Handles static wallpaper changes generated by WallpaperObserver events when
- // enableSeparateLockScreenEngine() is false.
- // TODO(b/266818039) Remove this method
- private void updateWallpapersLegacy(int event, String path) {
- final boolean moved = (event == MOVED_TO);
- final boolean written = (event == CLOSE_WRITE || moved);
- final File changedFile = new File(mWallpaperDir, path);
-
- // System and system+lock changes happen on the system wallpaper input file;
- // lock-only changes happen on the dedicated lock wallpaper input file
- final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile));
- final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile));
- int notifyColorsWhich = 0;
- WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged);
-
- if (DEBUG) {
- Slog.v(TAG, "Wallpaper file change: evt=" + event
- + " path=" + path
- + " sys=" + sysWallpaperChanged
- + " lock=" + lockWallpaperChanged
- + " imagePending=" + wallpaper.imageWallpaperPending
- + " mWhich=0x" + Integer.toHexString(wallpaper.mWhich)
- + " written=" + written);
- }
-
- if (moved && lockWallpaperChanged) {
- // We just migrated sys -> lock to preserve imagery for an impending
- // new system-only wallpaper. Tell keyguard about it and make sure it
- // has the right SELinux label.
- if (DEBUG) {
- Slog.i(TAG, "Sys -> lock MOVED_TO");
- }
- SELinux.restorecon(changedFile);
- notifyLockWallpaperChanged();
- notifyWallpaperColorsChanged(wallpaper, FLAG_LOCK);
- return;
- }
-
- synchronized (mLock) {
- if (sysWallpaperChanged || lockWallpaperChanged) {
- notifyCallbacksLocked(wallpaper);
- if (wallpaper.wallpaperComponent == null
- || event != CLOSE_WRITE // includes the MOVED_TO case
- || wallpaper.imageWallpaperPending) {
- if (written) {
- // The image source has finished writing the source image,
- // so we now produce the crop rect (in the background), and
- // only publish the new displayable (sub)image as a result
- // of that work.
- if (DEBUG) {
- Slog.v(TAG, "Wallpaper written; generating crop");
- }
- SELinux.restorecon(changedFile);
- if (moved) {
- // This is a restore, so generate the crop using any just-restored new
- // crop guidelines, making sure to preserve our local dimension hints.
- // We also make sure to reapply the correct SELinux label.
- if (DEBUG) {
- Slog.v(TAG, "moved-to, therefore restore; reloading metadata");
- }
- loadSettingsLocked(wallpaper.userId, true, FLAG_SYSTEM | FLAG_LOCK);
- }
- mWallpaperCropper.generateCrop(wallpaper);
- if (DEBUG) {
- Slog.v(TAG, "Crop done; invoking completion callback");
- }
- wallpaper.imageWallpaperPending = false;
- if (sysWallpaperChanged) {
- IRemoteCallback.Stub callback = new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) throws RemoteException {
- Slog.d(TAG, "publish system wallpaper changed!");
- notifyWallpaperChanged(wallpaper);
- }
- };
- // If this was the system wallpaper, rebind...
- bindWallpaperComponentLocked(mImageWallpaper, true,
- false, wallpaper, callback);
- notifyColorsWhich |= FLAG_SYSTEM;
- }
- if (lockWallpaperChanged
- || (wallpaper.mWhich & FLAG_LOCK) != 0) {
- if (DEBUG) {
- Slog.i(TAG, "Lock-relevant wallpaper changed");
- }
- // either a lock-only wallpaper commit or a system+lock event.
- // if it's system-plus-lock we need to wipe the lock bookkeeping;
- // we're falling back to displaying the system wallpaper there.
- if (!lockWallpaperChanged) {
- mLockWallpaperMap.remove(wallpaper.userId);
- }
- // and in any case, tell keyguard about it
- notifyLockWallpaperChanged();
- notifyColorsWhich |= FLAG_LOCK;
- }
-
- saveSettingsLocked(wallpaper.userId);
- // Notify the client immediately if only lockscreen wallpaper changed.
- if (lockWallpaperChanged && !sysWallpaperChanged) {
- notifyWallpaperChanged(wallpaper);
- }
- }
- }
- }
- }
-
- // Outside of the lock since it will synchronize itself
- if (notifyColorsWhich != 0) {
- notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich);
- }
- }
-
@Override
public void onEvent(int event, String path) {
- if (path == null) {
- return;
- }
-
- if (mIsLockscreenLiveWallpaperEnabled) {
- updateWallpapers(event, path);
- } else {
- updateWallpapersLegacy(event, path);
- }
+ if (path != null) updateWallpapers(event, path);
}
}
@@ -528,17 +406,6 @@
}
}
- private void notifyLockWallpaperChanged() {
- final IWallpaperManagerCallback cb = mKeyguardListener;
- if (cb != null) {
- try {
- cb.onWallpaperChanged();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify keyguard callback about wallpaper changes", e);
- }
- }
- }
-
void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) {
if (DEBUG) {
Slog.i(TAG, "Notifying wallpaper colors changed");
@@ -597,14 +464,12 @@
private void notifyColorListeners(@NonNull WallpaperColors wallpaperColors, int which,
int userId, int displayId) {
- final IWallpaperManagerCallback keyguardListener;
final ArrayList<IWallpaperManagerCallback> colorListeners = new ArrayList<>();
synchronized (mLock) {
final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
getWallpaperCallbacks(userId, displayId);
final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
getWallpaperCallbacks(UserHandle.USER_ALL, displayId);
- keyguardListener = mKeyguardListener;
if (currentUserColorListeners != null) {
final int count = currentUserColorListeners.beginBroadcast();
@@ -633,15 +498,6 @@
Slog.w(TAG, "onWallpaperColorsChanged() threw an exception", e);
}
}
-
- // Only shows Keyguard on default display
- if (keyguardListener != null && displayId == DEFAULT_DISPLAY) {
- try {
- keyguardListener.onWallpaperColorsChanged(wallpaperColors, which, userId);
- } catch (RemoteException e) {
- Slog.w(TAG, "keyguardListener.onWallpaperColorsChanged threw an exception", e);
- }
- }
}
/**
@@ -762,8 +618,6 @@
private final MyPackageMonitor mMonitor;
private final AppOpsManager mAppOpsManager;
- // TODO("b/264637309") probably move this in WallpaperDisplayUtils,
- // after logic is changed for the lockscreen lwp project
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayManager.DisplayListener() {
@@ -814,8 +668,6 @@
protected WallpaperData mLastWallpaper;
// The currently bound lock screen only wallpaper, or null if none
protected WallpaperData mLastLockWallpaper;
- private IWallpaperManagerCallback mKeyguardListener;
- private boolean mWaitingForUnlock;
/**
* Flag set to true after reboot if the home wallpaper is waiting for the device to be unlocked.
@@ -1017,8 +869,8 @@
if (!mWallpaper.wallpaperUpdating && mWallpaper.userId == mCurrentUserId) {
Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.wallpaperComponent
+ ", reverting to built-in wallpaper!");
- int which = mIsLockscreenLiveWallpaperEnabled ? mWallpaper.mWhich : FLAG_SYSTEM;
- clearWallpaperLocked(which, mWallpaper.userId, null);
+ int which = mWallpaper.mWhich;
+ clearWallpaperLocked(which, mWallpaper.userId, false, null);
}
}
};
@@ -1198,7 +1050,7 @@
} else {
// Timeout
Slog.w(TAG, "Reverting to built-in wallpaper!");
- clearWallpaperLocked(mWallpaper.mWhich, mWallpaper.userId, null);
+ clearWallpaperLocked(mWallpaper.mWhich, mWallpaper.userId, false, null);
final String flattened = wpService.flattenToString();
EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
flattened.substring(0, Math.min(flattened.length(),
@@ -1238,7 +1090,7 @@
if (mLmkLimitRebindRetries <= 0) {
Slog.w(TAG, "Reverting to built-in wallpaper due to lmk!");
clearWallpaperLocked(
- mWallpaper.mWhich, mWallpaper.userId, null);
+ mWallpaper.mWhich, mWallpaper.userId, false, null);
mLmkLimitRebindRetries = LMK_RECONNECT_REBIND_RETRIES;
return;
}
@@ -1257,7 +1109,7 @@
&& mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
> SystemClock.uptimeMillis()) {
Slog.w(TAG, "Reverting to built-in wallpaper!");
- clearWallpaperLocked(FLAG_SYSTEM, mWallpaper.userId, null);
+ clearWallpaperLocked(FLAG_SYSTEM, mWallpaper.userId, false, null);
} else {
mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
tryToRebind();
@@ -1294,19 +1146,8 @@
if (mImageWallpaper.equals(mWallpaper.wallpaperComponent)) {
return;
}
-
- // Live wallpapers always are system wallpapers unless lock screen live wp is
- // enabled.
- which = mIsLockscreenLiveWallpaperEnabled ? mWallpaper.mWhich : FLAG_SYSTEM;
+ which = mWallpaper.mWhich;
mWallpaper.primaryColors = primaryColors;
-
- // It's also the lock screen wallpaper when we don't have a bitmap in there.
- if (displayId == DEFAULT_DISPLAY) {
- final WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId);
- if (lockedWallpaper == null) {
- which |= FLAG_LOCK;
- }
- }
}
if (which != 0) {
notifyWallpaperColorsChangedOnDisplay(mWallpaper, which, displayId);
@@ -1492,9 +1333,7 @@
wallpaper, null)) {
Slog.w(TAG, "Wallpaper " + wpService
+ " no longer available; reverting to default");
- int which = mIsLockscreenLiveWallpaperEnabled
- ? wallpaper.mWhich : FLAG_SYSTEM;
- clearWallpaperLocked(which, wallpaper.userId, null);
+ clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null);
}
}
}
@@ -1568,7 +1407,6 @@
boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) {
boolean changed = false;
- int which = mIsLockscreenLiveWallpaperEnabled ? wallpaper.mWhich : FLAG_SYSTEM;
if (wallpaper.wallpaperComponent != null) {
int change = isPackageDisappearing(wallpaper.wallpaperComponent
.getPackageName());
@@ -1578,7 +1416,7 @@
if (doit) {
Slog.w(TAG, "Wallpaper uninstalled, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(which, wallpaper.userId, null);
+ clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null);
}
}
}
@@ -1599,7 +1437,7 @@
} catch (NameNotFoundException e) {
Slog.w(TAG, "Wallpaper component gone, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(which, wallpaper.userId, null);
+ clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null);
}
}
if (wallpaper.nextWallpaperComponent != null
@@ -1686,9 +1524,6 @@
mColorsChangedListeners = new SparseArray<>();
mWallpaperDataParser = new WallpaperDataParser(mContext, mWallpaperDisplayHelper,
mWallpaperCropper);
-
- mIsLockscreenLiveWallpaperEnabled =
- SystemProperties.getBoolean("persist.wm.debug.lockscreen_live_wallpaper", true);
mIsMultiCropEnabled =
SystemProperties.getBoolean("persist.wm.debug.wallpaper_multi_crop", false);
LocalServices.addService(WallpaperManagerInternal.class, new LocalService());
@@ -1755,8 +1590,7 @@
if (DEBUG) {
Slog.i(TAG, "Unable to regenerate crop; resetting");
}
- int which = isLockscreenLiveWallpaperEnabled() ? wallpaper.mWhich : FLAG_SYSTEM;
- clearWallpaperLocked(which, UserHandle.USER_SYSTEM, null);
+ clearWallpaperLocked(wallpaper.mWhich, UserHandle.USER_SYSTEM, false, null);
}
} else {
if (DEBUG) {
@@ -1883,29 +1717,19 @@
public void onUnlockUser(final int userId) {
synchronized (mLock) {
if (mCurrentUserId == userId) {
- if (mIsLockscreenLiveWallpaperEnabled) {
- if (mHomeWallpaperWaitingForUnlock) {
- final WallpaperData systemWallpaper =
- getWallpaperSafeLocked(userId, FLAG_SYSTEM);
- switchWallpaper(systemWallpaper, null);
- // TODO(b/278261563): call notifyCallbacksLocked inside switchWallpaper
- notifyCallbacksLocked(systemWallpaper);
- }
- if (mLockWallpaperWaitingForUnlock) {
- final WallpaperData lockWallpaper =
- getWallpaperSafeLocked(userId, FLAG_LOCK);
- switchWallpaper(lockWallpaper, null);
- notifyCallbacksLocked(lockWallpaper);
- }
- }
-
- if (mWaitingForUnlock && !mIsLockscreenLiveWallpaperEnabled) {
- // the desired wallpaper is not direct-boot aware, load it now
+ if (mHomeWallpaperWaitingForUnlock) {
final WallpaperData systemWallpaper =
getWallpaperSafeLocked(userId, FLAG_SYSTEM);
switchWallpaper(systemWallpaper, null);
+ // TODO(b/278261563): call notifyCallbacksLocked inside switchWallpaper
notifyCallbacksLocked(systemWallpaper);
}
+ if (mLockWallpaperWaitingForUnlock) {
+ final WallpaperData lockWallpaper =
+ getWallpaperSafeLocked(userId, FLAG_LOCK);
+ switchWallpaper(lockWallpaper, null);
+ notifyCallbacksLocked(lockWallpaper);
+ }
// Make sure that the SELinux labeling of all the relevant files is correct.
// This corrects for mislabeling bugs that might have arisen from move-to
@@ -1954,21 +1778,15 @@
}
mCurrentUserId = userId;
systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
-
- if (mIsLockscreenLiveWallpaperEnabled) {
- lockWallpaper = systemWallpaper.mWhich == (FLAG_LOCK | FLAG_SYSTEM)
- ? systemWallpaper : getWallpaperSafeLocked(userId, FLAG_LOCK);
- } else {
- final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId);
- lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper;
- }
+ lockWallpaper = systemWallpaper.mWhich == (FLAG_LOCK | FLAG_SYSTEM)
+ ? systemWallpaper : getWallpaperSafeLocked(userId, FLAG_LOCK);
// Not started watching yet, in case wallpaper data was loaded for other reasons.
if (systemWallpaper.wallpaperObserver == null) {
systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
systemWallpaper.wallpaperObserver.startWatching();
}
- if (mIsLockscreenLiveWallpaperEnabled && lockWallpaper != systemWallpaper) {
+ if (lockWallpaper != systemWallpaper) {
switchWallpaper(lockWallpaper, null);
}
switchWallpaper(systemWallpaper, reply);
@@ -1988,11 +1806,8 @@
void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
synchronized (mLock) {
- mWaitingForUnlock = false;
- if (mIsLockscreenLiveWallpaperEnabled) {
- if ((wallpaper.mWhich & FLAG_SYSTEM) != 0) mHomeWallpaperWaitingForUnlock = false;
- if ((wallpaper.mWhich & FLAG_LOCK) != 0) mLockWallpaperWaitingForUnlock = false;
- }
+ if ((wallpaper.mWhich & FLAG_SYSTEM) != 0) mHomeWallpaperWaitingForUnlock = false;
+ if ((wallpaper.mWhich & FLAG_LOCK) != 0) mLockWallpaperWaitingForUnlock = false;
final ComponentName cname = wallpaper.wallpaperComponent != null ?
wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
@@ -2006,37 +1821,19 @@
} catch (RemoteException e) {
Slog.w(TAG, "Failure starting previous wallpaper; clearing", e);
}
-
- if (mIsLockscreenLiveWallpaperEnabled) {
- onSwitchWallpaperFailLocked(wallpaper, reply, si);
- return;
- }
-
- if (si == null) {
- clearWallpaperLocked(FLAG_SYSTEM, wallpaper.userId, reply);
- } else {
- Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
- // We might end up persisting the current wallpaper data
- // while locked, so pretend like the component was actually
- // bound into place
- wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
- final WallpaperData fallback = new WallpaperData(wallpaper.userId, FLAG_LOCK);
- bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
- mWaitingForUnlock = true;
- }
+ onSwitchWallpaperFailLocked(wallpaper, reply, si);
}
}
}
/**
* Fallback method if a wallpaper fails to load on boot or after a user switch.
- * Only called if mIsLockscreenLiveWallpaperEnabled is true.
*/
private void onSwitchWallpaperFailLocked(
WallpaperData wallpaper, IRemoteCallback reply, ServiceInfo serviceInfo) {
if (serviceInfo == null) {
- clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, reply);
+ clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, reply);
return;
}
Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
@@ -2067,12 +1864,8 @@
WallpaperData data = null;
synchronized (mLock) {
- if (mIsLockscreenLiveWallpaperEnabled) {
- boolean fromForeground = isFromForegroundApp(callingPackage);
- clearWallpaperLocked(which, userId, fromForeground, null);
- } else {
- clearWallpaperLocked(which, userId, null);
- }
+ boolean fromForeground = isFromForegroundApp(callingPackage);
+ clearWallpaperLocked(which, userId, fromForeground, null);
if (which == FLAG_LOCK) {
data = mLockWallpaperMap.get(userId);
@@ -2153,91 +1946,6 @@
}
}
- // TODO(b/266818039) remove
- private void clearWallpaperLocked(int which, int userId, IRemoteCallback reply) {
-
- if (mIsLockscreenLiveWallpaperEnabled) {
- clearWallpaperLocked(which, userId, false, reply);
- return;
- }
-
- if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
- throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear");
- }
-
- WallpaperData wallpaper = null;
- if (which == FLAG_LOCK) {
- wallpaper = mLockWallpaperMap.get(userId);
- if (wallpaper == null) {
- // It's already gone; we're done.
- if (DEBUG) {
- Slog.i(TAG, "Lock wallpaper already cleared");
- }
- return;
- }
- } else {
- wallpaper = mWallpaperMap.get(userId);
- if (wallpaper == null) {
- // Might need to bring it in the first time to establish our rewrite
- loadSettingsLocked(userId, false, FLAG_SYSTEM);
- wallpaper = mWallpaperMap.get(userId);
- }
- }
- if (wallpaper == null) {
- return;
- }
-
- final long ident = Binder.clearCallingIdentity();
- try {
- if (clearWallpaperBitmaps(wallpaper)) {
- if (which == FLAG_LOCK) {
- mLockWallpaperMap.remove(userId);
- final IWallpaperManagerCallback cb = mKeyguardListener;
- if (cb != null) {
- if (DEBUG) {
- Slog.i(TAG, "Notifying keyguard of lock wallpaper clear");
- }
- try {
- cb.onWallpaperChanged();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify keyguard after wallpaper clear", e);
- }
- }
- saveSettingsLocked(userId);
- return;
- }
- }
-
- RuntimeException e = null;
- try {
- wallpaper.primaryColors = null;
- wallpaper.imageWallpaperPending = false;
- if (userId != mCurrentUserId) return;
- if (bindWallpaperComponentLocked(null, true, false, wallpaper, reply)) {
- return;
- }
- } catch (IllegalArgumentException e1) {
- e = e1;
- }
-
- // This can happen if the default wallpaper component doesn't
- // exist. This should be a system configuration problem, but
- // let's not let it crash the system and just live with no
- // wallpaper.
- Slog.e(TAG, "Default wallpaper component not found!", e);
- clearWallpaperComponentLocked(wallpaper);
- if (reply != null) {
- try {
- reply.sendResult(null);
- } catch (RemoteException e1) {
- Slog.w(TAG, "Failed to notify callback after wallpaper clear", e1);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
private boolean hasCrossUserPermission() {
final int interactPermission =
mContext.checkCallingPermission(INTERACT_ACROSS_USERS_FULL);
@@ -2615,45 +2323,20 @@
* @param animationDuration Duration of the animation, or 0 when immediate.
*/
public void setInAmbientMode(boolean inAmbientMode, long animationDuration) {
- if (mIsLockscreenLiveWallpaperEnabled) {
- List<IWallpaperEngine> engines = new ArrayList<>();
- synchronized (mLock) {
- mInAmbientMode = inAmbientMode;
- for (WallpaperData data : getActiveWallpapers()) {
- if (data.connection.mInfo == null
- || data.connection.mInfo.supportsAmbientMode()) {
- // TODO(multi-display) Extends this method with specific display.
- IWallpaperEngine engine = data.connection
- .getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
- if (engine != null) engines.add(engine);
- }
- }
- }
- for (IWallpaperEngine engine : engines) {
- try {
- engine.setInAmbientMode(inAmbientMode, animationDuration);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to set ambient mode", e);
- }
- }
- return;
- }
-
- final IWallpaperEngine engine;
+ List<IWallpaperEngine> engines = new ArrayList<>();
synchronized (mLock) {
mInAmbientMode = inAmbientMode;
- final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
- // The wallpaper info is null for image wallpaper, also use the engine in this case.
- if (data != null && data.connection != null && (data.connection.mInfo == null
- || data.connection.mInfo.supportsAmbientMode())) {
- // TODO(multi-display) Extends this method with specific display.
- engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
- } else {
- engine = null;
+ for (WallpaperData data : getActiveWallpapers()) {
+ if (data.connection.mInfo == null
+ || data.connection.mInfo.supportsAmbientMode()) {
+ // TODO(multi-display) Extends this method with specific display.
+ IWallpaperEngine engine = data.connection
+ .getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
+ if (engine != null) engines.add(engine);
+ }
}
}
-
- if (engine != null) {
+ for (IWallpaperEngine engine : engines) {
try {
engine.setInAmbientMode(inAmbientMode, animationDuration);
} catch (RemoteException e) {
@@ -2664,11 +2347,8 @@
private void pauseOrResumeRenderingImmediately(boolean pause) {
synchronized (mLock) {
- final WallpaperData[] wallpapers = mIsLockscreenLiveWallpaperEnabled
- ? getActiveWallpapers() : new WallpaperData[] {
- mWallpaperMap.get(mCurrentUserId) };
- for (WallpaperData data : wallpapers) {
- if (data.connection == null || data.connection.mInfo == null) {
+ for (WallpaperData data : getActiveWallpapers()) {
+ if (data.connection.mInfo == null) {
continue;
}
if (pause || LocalServices.getService(ActivityTaskManagerInternal.class)
@@ -2697,34 +2377,17 @@
public void notifyWakingUp(int x, int y, @NonNull Bundle extras) {
checkCallerIsSystemOrSystemUi();
synchronized (mLock) {
- if (mIsLockscreenLiveWallpaperEnabled) {
- for (WallpaperData data : getActiveWallpapers()) {
- data.connection.forEachDisplayConnector(displayConnector -> {
- if (displayConnector.mEngine != null) {
- try {
- displayConnector.mEngine.dispatchWallpaperCommand(
- WallpaperManager.COMMAND_WAKING_UP, x, y, -1, extras);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to dispatch COMMAND_WAKING_UP", e);
- }
+ for (WallpaperData data : getActiveWallpapers()) {
+ data.connection.forEachDisplayConnector(displayConnector -> {
+ if (displayConnector.mEngine != null) {
+ try {
+ displayConnector.mEngine.dispatchWallpaperCommand(
+ WallpaperManager.COMMAND_WAKING_UP, x, y, -1, extras);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to dispatch COMMAND_WAKING_UP", e);
}
- });
- }
- return;
- }
- final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
- if (data != null && data.connection != null) {
- data.connection.forEachDisplayConnector(
- displayConnector -> {
- if (displayConnector.mEngine != null) {
- try {
- displayConnector.mEngine.dispatchWallpaperCommand(
- WallpaperManager.COMMAND_WAKING_UP, x, y, -1, extras);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to dispatch COMMAND_WAKING_UP", e);
- }
- }
- });
+ }
+ });
}
}
}
@@ -2735,36 +2398,18 @@
public void notifyGoingToSleep(int x, int y, @NonNull Bundle extras) {
checkCallerIsSystemOrSystemUi();
synchronized (mLock) {
- if (mIsLockscreenLiveWallpaperEnabled) {
- for (WallpaperData data : getActiveWallpapers()) {
- data.connection.forEachDisplayConnector(displayConnector -> {
- if (displayConnector.mEngine != null) {
- try {
- displayConnector.mEngine.dispatchWallpaperCommand(
- WallpaperManager.COMMAND_GOING_TO_SLEEP, x, y, -1,
- extras);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to dispatch COMMAND_GOING_TO_SLEEP", e);
- }
+ for (WallpaperData data : getActiveWallpapers()) {
+ data.connection.forEachDisplayConnector(displayConnector -> {
+ if (displayConnector.mEngine != null) {
+ try {
+ displayConnector.mEngine.dispatchWallpaperCommand(
+ WallpaperManager.COMMAND_GOING_TO_SLEEP, x, y, -1,
+ extras);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to dispatch COMMAND_GOING_TO_SLEEP", e);
}
- });
- }
- return;
- }
- final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
- if (data != null && data.connection != null) {
- data.connection.forEachDisplayConnector(
- displayConnector -> {
- if (displayConnector.mEngine != null) {
- try {
- displayConnector.mEngine.dispatchWallpaperCommand(
- WallpaperManager.COMMAND_GOING_TO_SLEEP, x, y, -1,
- extras);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to dispatch COMMAND_GOING_TO_SLEEP", e);
- }
- }
- });
+ }
+ });
}
}
}
@@ -2774,35 +2419,18 @@
*/
private void notifyScreenTurnedOn(int displayId) {
synchronized (mLock) {
- if (mIsLockscreenLiveWallpaperEnabled) {
- for (WallpaperData data : getActiveWallpapers()) {
- if (data.connection.containsDisplay(displayId)) {
- final IWallpaperEngine engine = data.connection
- .getDisplayConnectorOrCreate(displayId).mEngine;
- if (engine != null) {
- try {
- engine.onScreenTurnedOn();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify that the screen turned on", e);
- }
+ for (WallpaperData data : getActiveWallpapers()) {
+ if (data.connection.containsDisplay(displayId)) {
+ final IWallpaperEngine engine = data.connection
+ .getDisplayConnectorOrCreate(displayId).mEngine;
+ if (engine != null) {
+ try {
+ engine.onScreenTurnedOn();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to notify that the screen turned on", e);
}
}
}
- return;
- }
- final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
- if (data != null
- && data.connection != null
- && data.connection.containsDisplay(displayId)) {
- final IWallpaperEngine engine = data.connection
- .getDisplayConnectorOrCreate(displayId).mEngine;
- if (engine != null) {
- try {
- engine.onScreenTurnedOn();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify that the screen turned on", e);
- }
- }
}
}
}
@@ -2812,35 +2440,18 @@
*/
private void notifyScreenTurningOn(int displayId) {
synchronized (mLock) {
- if (mIsLockscreenLiveWallpaperEnabled) {
- for (WallpaperData data : getActiveWallpapers()) {
- if (data.connection.containsDisplay(displayId)) {
- final IWallpaperEngine engine = data.connection
- .getDisplayConnectorOrCreate(displayId).mEngine;
- if (engine != null) {
- try {
- engine.onScreenTurningOn();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify that the screen is turning on", e);
- }
+ for (WallpaperData data : getActiveWallpapers()) {
+ if (data.connection.containsDisplay(displayId)) {
+ final IWallpaperEngine engine = data.connection
+ .getDisplayConnectorOrCreate(displayId).mEngine;
+ if (engine != null) {
+ try {
+ engine.onScreenTurningOn();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to notify that the screen is turning on", e);
}
}
}
- return;
- }
- final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
- if (data != null
- && data.connection != null
- && data.connection.containsDisplay(displayId)) {
- final IWallpaperEngine engine = data.connection
- .getDisplayConnectorOrCreate(displayId).mEngine;
- if (engine != null) {
- try {
- engine.onScreenTurningOn();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify that the screen is turning on", e);
- }
- }
}
}
}
@@ -2850,25 +2461,7 @@
*/
private void notifyKeyguardGoingAway() {
synchronized (mLock) {
- if (mIsLockscreenLiveWallpaperEnabled) {
- for (WallpaperData data : getActiveWallpapers()) {
- data.connection.forEachDisplayConnector(displayConnector -> {
- if (displayConnector.mEngine != null) {
- try {
- displayConnector.mEngine.dispatchWallpaperCommand(
- WallpaperManager.COMMAND_KEYGUARD_GOING_AWAY,
- -1, -1, -1, new Bundle());
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify that the keyguard is going away", e);
- }
- }
- });
- }
- return;
- }
-
- final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
- if (data != null && data.connection != null) {
+ for (WallpaperData data : getActiveWallpapers()) {
data.connection.forEachDisplayConnector(displayConnector -> {
if (displayConnector.mEngine != null) {
try {
@@ -2884,15 +2477,6 @@
}
}
- @Override
- public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
- checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
- synchronized (mLock) {
- mKeyguardListener = cb;
- }
- return true;
- }
-
private WallpaperData[] getActiveWallpapers() {
WallpaperData systemWallpaper = mWallpaperMap.get(mCurrentUserId);
WallpaperData lockWallpaper = mLockWallpaperMap.get(mCurrentUserId);
@@ -2904,12 +2488,11 @@
: new WallpaperData[0];
}
- // TODO(b/266818039) remove
private WallpaperData[] getWallpapers() {
WallpaperData systemWallpaper = mWallpaperMap.get(mCurrentUserId);
WallpaperData lockWallpaper = mLockWallpaperMap.get(mCurrentUserId);
boolean systemValid = systemWallpaper != null;
- boolean lockValid = lockWallpaper != null && isLockscreenLiveWallpaperEnabled();
+ boolean lockValid = lockWallpaper != null;
return systemValid && lockValid ? new WallpaperData[]{systemWallpaper, lockWallpaper}
: systemValid ? new WallpaperData[]{systemWallpaper}
: lockValid ? new WallpaperData[]{lockWallpaper}
@@ -3043,54 +2626,29 @@
lockWallpaper.mWallpaperDimAmount = maxDimAmount;
}
- if (mIsLockscreenLiveWallpaperEnabled) {
- boolean changed = false;
- for (WallpaperData wp : getActiveWallpapers()) {
- if (wp != null && wp.connection != null) {
- wp.connection.forEachDisplayConnector(connector -> {
- if (connector.mEngine != null) {
- try {
- connector.mEngine.applyDimming(maxDimAmount);
- } catch (RemoteException e) {
- Slog.w(TAG, "Can't apply dimming on wallpaper display "
- + "connector", e);
- }
- }
- });
- // Need to extract colors again to re-calculate dark hints after
- // applying dimming.
- wp.mIsColorExtractedFromDim = true;
- pendingColorExtraction.add(wp);
- changed = true;
- }
- }
- if (changed) {
- saveSettingsLocked(wallpaper.userId);
- }
- } else {
- if (wallpaper.connection != null) {
- wallpaper.connection.forEachDisplayConnector(connector -> {
+ boolean changed = false;
+ for (WallpaperData wp : getActiveWallpapers()) {
+ if (wp != null && wp.connection != null) {
+ wp.connection.forEachDisplayConnector(connector -> {
if (connector.mEngine != null) {
try {
connector.mEngine.applyDimming(maxDimAmount);
} catch (RemoteException e) {
- Slog.w(TAG,
- "Can't apply dimming on wallpaper display connector",
- e);
+ Slog.w(TAG, "Can't apply dimming on wallpaper display "
+ + "connector", e);
}
}
});
// Need to extract colors again to re-calculate dark hints after
// applying dimming.
- wallpaper.mIsColorExtractedFromDim = true;
- notifyWallpaperColorsChanged(wallpaper, FLAG_SYSTEM);
- if (lockWallpaper != null) {
- lockWallpaper.mIsColorExtractedFromDim = true;
- notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
- }
- saveSettingsLocked(wallpaper.userId);
+ wp.mIsColorExtractedFromDim = true;
+ pendingColorExtraction.add(wp);
+ changed = true;
}
}
+ if (changed) {
+ saveSettingsLocked(wallpaper.userId);
+ }
}
for (WallpaperData wp: pendingColorExtraction) {
notifyWallpaperColorsChanged(wp, wp.mWhich);
@@ -3246,10 +2804,7 @@
if (which == FLAG_SYSTEM && systemIsStatic && systemIsBoth) {
Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
+ " updating system wallpaper");
- if (!migrateStaticSystemToLockWallpaperLocked(userId)
- && !isLockscreenLiveWallpaperEnabled()) {
- which |= FLAG_LOCK;
- }
+ migrateStaticSystemToLockWallpaperLocked(userId);
}
wallpaper = getWallpaperSafeLocked(userId, which);
@@ -3277,13 +2832,13 @@
}
}
- private boolean migrateStaticSystemToLockWallpaperLocked(int userId) {
+ private void migrateStaticSystemToLockWallpaperLocked(int userId) {
WallpaperData sysWP = mWallpaperMap.get(userId);
if (sysWP == null) {
if (DEBUG) {
Slog.i(TAG, "No system wallpaper? Not tracking for lock-only");
}
- return true;
+ return;
}
// We know a-priori that there is no lock-only wallpaper currently
@@ -3297,25 +2852,21 @@
// Migrate the bitmap files outright; no need to copy
try {
- if (!mIsLockscreenLiveWallpaperEnabled || sysWP.getWallpaperFile().exists()) {
+ if (sysWP.getWallpaperFile().exists()) {
Os.rename(sysWP.getWallpaperFile().getAbsolutePath(),
lockWP.getWallpaperFile().getAbsolutePath());
}
- if (!mIsLockscreenLiveWallpaperEnabled || sysWP.getCropFile().exists()) {
+ if (sysWP.getCropFile().exists()) {
Os.rename(sysWP.getCropFile().getAbsolutePath(),
lockWP.getCropFile().getAbsolutePath());
}
mLockWallpaperMap.put(userId, lockWP);
- if (mIsLockscreenLiveWallpaperEnabled) {
- SELinux.restorecon(lockWP.getWallpaperFile());
- mLastLockWallpaper = lockWP;
- }
- return true;
+ SELinux.restorecon(lockWP.getWallpaperFile());
+ mLastLockWallpaper = lockWP;
} catch (ErrnoException e) {
// can happen when migrating default wallpaper (which is not stored in wallpaperFile)
Slog.w(TAG, "Couldn't migrate system wallpaper: " + e.getMessage());
clearWallpaperBitmaps(lockWP);
- return false;
}
}
@@ -3372,13 +2923,8 @@
@VisibleForTesting
boolean setWallpaperComponent(ComponentName name, String callingPackage,
@SetWallpaperFlags int which, int userId) {
- if (mIsLockscreenLiveWallpaperEnabled) {
- boolean fromForeground = isFromForegroundApp(callingPackage);
- return setWallpaperComponentInternal(name, which, userId, false, fromForeground, null);
- } else {
- setWallpaperComponentInternalLegacy(name, callingPackage, which, userId);
- return true;
- }
+ boolean fromForeground = isFromForegroundApp(callingPackage);
+ return setWallpaperComponentInternal(name, which, userId, false, fromForeground, null);
}
private boolean setWallpaperComponentInternal(ComponentName name, @SetWallpaperFlags int which,
@@ -3491,87 +3037,6 @@
return bindSuccess;
}
- // TODO(b/266818039) Remove this method
- private void setWallpaperComponentInternalLegacy(ComponentName name, String callingPackage,
- @SetWallpaperFlags int which, int userId) {
- userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
- false /* all */, true /* full */, "changing live wallpaper", null /* pkg */);
- checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
-
- int legacyWhich = FLAG_SYSTEM;
- boolean shouldNotifyColors = false;
- WallpaperData wallpaper;
-
- synchronized (mLock) {
- Slog.v(TAG, "setWallpaperComponentLegacy name=" + name + ", which=" + which);
- wallpaper = mWallpaperMap.get(userId);
- if (wallpaper == null) {
- throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
- }
- final long ident = Binder.clearCallingIdentity();
-
- // Live wallpapers can't be specified for keyguard. If we're using a static
- // system+lock image currently, migrate the system wallpaper to be a lock-only
- // image as part of making a different live component active as the system
- // wallpaper.
- if (mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
- if (mLockWallpaperMap.get(userId) == null) {
- // We're using the static imagery and there is no lock-specific image in place,
- // therefore it's a shared system+lock image that we need to migrate.
- Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
- + "updating system wallpaper");
- if (!migrateStaticSystemToLockWallpaperLocked(userId)) {
- which |= FLAG_LOCK;
- }
- }
- }
-
- // New live wallpaper is also a lock wallpaper if nothing is set
- if (mLockWallpaperMap.get(userId) == null) {
- legacyWhich |= FLAG_LOCK;
- }
-
- try {
- wallpaper.imageWallpaperPending = false;
- wallpaper.mWhich = which;
- wallpaper.fromForegroundApp = isFromForegroundApp(callingPackage);
- boolean same = changingToSame(name, wallpaper);
-
- // force rebind when reapplying a system-only wallpaper to system+lock
- boolean forceRebind = same && mLockWallpaperMap.get(userId) != null
- && which == (FLAG_SYSTEM | FLAG_LOCK);
- if (bindWallpaperComponentLocked(name, forceRebind, true, wallpaper, null)) {
- if (!same) {
- wallpaper.primaryColors = null;
- } else {
- if (wallpaper.connection != null) {
- wallpaper.connection.forEachDisplayConnector(displayConnector -> {
- try {
- if (displayConnector.mEngine != null) {
- displayConnector.mEngine.dispatchWallpaperCommand(
- COMMAND_REAPPLY, 0, 0, 0, null);
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Error sending apply message to wallpaper", e);
- }
- });
- }
- }
- wallpaper.wallpaperId = makeWallpaperIdLocked();
- notifyCallbacksLocked(wallpaper);
- shouldNotifyColors = true;
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- if (shouldNotifyColors) {
- notifyWallpaperColorsChanged(wallpaper, legacyWhich);
- notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
- }
- }
-
/**
* Determines if the given component name is the default component. Note: a null name can be
* used to represent the default component.
@@ -3743,21 +3208,11 @@
Slog.w(TAG, msg);
return false;
}
- if (mIsLockscreenLiveWallpaperEnabled) {
- maybeDetachLastWallpapers(wallpaper);
- } else if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null
- && !wallpaper.equals(mFallbackWallpaper)) {
- detachWallpaperLocked(mLastWallpaper);
- }
+ maybeDetachLastWallpapers(wallpaper);
wallpaper.wallpaperComponent = componentName;
wallpaper.connection = newConn;
newConn.mReply = reply;
- if (mIsLockscreenLiveWallpaperEnabled) {
- updateCurrentWallpapers(wallpaper);
- } else if (wallpaper.userId == mCurrentUserId && !wallpaper.equals(
- mFallbackWallpaper)) {
- mLastWallpaper = wallpaper;
- }
+ updateCurrentWallpapers(wallpaper);
updateFallbackConnection();
} catch (RemoteException e) {
String msg = "Remote exception for " + componentName + "\n" + e;
@@ -3773,7 +3228,6 @@
}
// Updates tracking of the currently bound wallpapers.
- // Assumes isLockscreenLiveWallpaperEnabled is true.
private void updateCurrentWallpapers(WallpaperData newWallpaper) {
if (newWallpaper.userId != mCurrentUserId || newWallpaper.equals(mFallbackWallpaper)) {
return;
@@ -3787,8 +3241,7 @@
}
}
- // Detaches previously bound wallpapers if no longer in use. Assumes
- // isLockscreenLiveWallpaperEnabled is true.
+ // Detaches previously bound wallpapers if no longer in use.
private void maybeDetachLastWallpapers(WallpaperData newWallpaper) {
if (newWallpaper.userId != mCurrentUserId || newWallpaper.equals(mFallbackWallpaper)) {
return;
@@ -3981,11 +3434,6 @@
}
@Override
- public boolean isLockscreenLiveWallpaperEnabled() {
- return mIsLockscreenLiveWallpaperEnabled;
- }
-
- @Override
public boolean isMultiCropEnabled() {
return mIsMultiCropEnabled;
}
@@ -4074,13 +3522,12 @@
private void loadSettingsLocked(int userId, boolean keepDimensionHints, int which) {
initializeFallbackWallpaper();
- WallpaperData wallpaperData = mWallpaperMap.get(userId);
- WallpaperData lockWallpaperData = mLockWallpaperMap.get(userId);
+ boolean restoreFromOld = !mWallpaperMap.contains(userId);
WallpaperDataParser.WallpaperLoadingResult result = mWallpaperDataParser.loadSettingsLocked(
- userId, keepDimensionHints, wallpaperData, lockWallpaperData, which);
+ userId, keepDimensionHints, restoreFromOld, which);
- boolean updateSystem = !mIsLockscreenLiveWallpaperEnabled || (which & FLAG_SYSTEM) != 0;
- boolean updateLock = !mIsLockscreenLiveWallpaperEnabled || (which & FLAG_LOCK) != 0;
+ boolean updateSystem = (which & FLAG_SYSTEM) != 0;
+ boolean updateLock = (which & FLAG_LOCK) != 0;
if (updateSystem) mWallpaperMap.put(userId, result.getSystemWallpaperData());
if (updateLock) {
@@ -4243,8 +3690,6 @@
if (mFallbackWallpaper != null) {
dumpWallpaper(mFallbackWallpaper, pw);
}
- pw.print("mIsLockscreenLiveWallpaperEnabled=");
- pw.println(mIsLockscreenLiveWallpaperEnabled);
}
}
}
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 06448d0..022ef61 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -28,6 +28,7 @@
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.media.projection.IMediaProjectionManager;
import android.os.IBinder;
@@ -36,10 +37,12 @@
import android.view.ContentRecordingSession;
import android.view.ContentRecordingSession.RecordContent;
import android.view.Display;
+import android.view.DisplayInfo;
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.server.display.feature.DisplayManagerFlags;
/**
* Manages content recording for a particular {@link DisplayContent}.
@@ -47,6 +50,16 @@
final class ContentRecorder implements WindowContainerListener {
/**
+ * Maximum acceptable anisotropy for the output image.
+ *
+ * Necessary to avoid unnecessary scaling when the anisotropy is almost the same, as it is not
+ * exact anyway. For external displays, we expect an anisoptry of about 2% even if the pixels
+ * are, in fact, square due to the imprecision of the display's actual size (rounded to the
+ * nearest cm).
+ */
+ private static final float MAX_ANISOTROPY = 0.025f;
+
+ /**
* The display content this class is handling recording for.
*/
@NonNull
@@ -87,15 +100,20 @@
@Configuration.Orientation
private int mLastOrientation = ORIENTATION_UNDEFINED;
+ private final boolean mCorrectForAnisotropicPixels;
+
ContentRecorder(@NonNull DisplayContent displayContent) {
- this(displayContent, new RemoteMediaProjectionManagerWrapper(displayContent.mDisplayId));
+ this(displayContent, new RemoteMediaProjectionManagerWrapper(displayContent.mDisplayId),
+ new DisplayManagerFlags().isConnectedDisplayManagementEnabled());
}
@VisibleForTesting
ContentRecorder(@NonNull DisplayContent displayContent,
- @NonNull MediaProjectionManagerWrapper mediaProjectionManager) {
+ @NonNull MediaProjectionManagerWrapper mediaProjectionManager,
+ boolean correctForAnisotropicPixels) {
mDisplayContent = displayContent;
mMediaProjectionManager = mediaProjectionManager;
+ mCorrectForAnisotropicPixels = correctForAnisotropicPixels;
}
/**
@@ -460,6 +478,33 @@
}
}
+ private void computeScaling(int inputSizeX, int inputSizeY,
+ float inputDpiX, float inputDpiY,
+ int outputSizeX, int outputSizeY,
+ float outputDpiX, float outputDpiY,
+ PointF scaleOut) {
+ float relAnisotropy = (inputDpiY / inputDpiX) / (outputDpiY / outputDpiX);
+ if (!mCorrectForAnisotropicPixels
+ || (relAnisotropy > (1 - MAX_ANISOTROPY) && relAnisotropy < (1 + MAX_ANISOTROPY))) {
+ // Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the
+ // output surface.
+ float scaleX = outputSizeX / (float) inputSizeX;
+ float scaleY = outputSizeY / (float) inputSizeY;
+ float scale = Math.min(scaleX, scaleY);
+ scaleOut.x = scale;
+ scaleOut.y = scale;
+ return;
+ }
+
+ float relDpiX = outputDpiX / inputDpiX;
+ float relDpiY = outputDpiY / inputDpiY;
+
+ float scale = Math.min(outputSizeX / relDpiX / inputSizeX,
+ outputSizeY / relDpiY / inputSizeY);
+ scaleOut.x = scale * relDpiX;
+ scaleOut.y = scale * relDpiY;
+ }
+
/**
* Apply transformations to the mirrored surface to ensure the captured contents are scaled to
* fit and centred in the output surface.
@@ -473,13 +518,19 @@
*/
@VisibleForTesting void updateMirroredSurface(SurfaceControl.Transaction transaction,
Rect recordedContentBounds, Point surfaceSize) {
- // Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the
- // output surface.
- float scaleX = surfaceSize.x / (float) recordedContentBounds.width();
- float scaleY = surfaceSize.y / (float) recordedContentBounds.height();
- float scale = Math.min(scaleX, scaleY);
- int scaledWidth = Math.round(scale * (float) recordedContentBounds.width());
- int scaledHeight = Math.round(scale * (float) recordedContentBounds.height());
+
+ DisplayInfo inputDisplayInfo = mRecordedWindowContainer.mDisplayContent.getDisplayInfo();
+ DisplayInfo outputDisplayInfo = mDisplayContent.getDisplayInfo();
+
+ PointF scale = new PointF();
+ computeScaling(recordedContentBounds.width(), recordedContentBounds.height(),
+ inputDisplayInfo.physicalXDpi, inputDisplayInfo.physicalYDpi,
+ surfaceSize.x, surfaceSize.y,
+ outputDisplayInfo.physicalXDpi, outputDisplayInfo.physicalYDpi,
+ scale);
+
+ int scaledWidth = Math.round(scale.x * (float) recordedContentBounds.width());
+ int scaledHeight = Math.round(scale.y * (float) recordedContentBounds.height());
// Calculate the shift to apply to the root mirror SurfaceControl to centre the mirrored
// contents in the output surface.
@@ -493,10 +544,10 @@
}
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Content Recording: Apply transformations of shift %d x %d, scale %f, crop (aka "
- + "recorded content size) %d x %d for display %d; display has size %d x "
- + "%d; surface has size %d x %d",
- shiftedX, shiftedY, scale, recordedContentBounds.width(),
+ "Content Recording: Apply transformations of shift %d x %d, scale %f x %f, crop "
+ + "(aka recorded content size) %d x %d for display %d; display has size "
+ + "%d x %d; surface has size %d x %d",
+ shiftedX, shiftedY, scale.x, scale.y, recordedContentBounds.width(),
recordedContentBounds.height(), mDisplayContent.getDisplayId(),
mDisplayContent.getConfiguration().screenWidthDp,
mDisplayContent.getConfiguration().screenHeightDp, surfaceSize.x, surfaceSize.y);
@@ -508,7 +559,7 @@
recordedContentBounds.height())
// Scale the root mirror SurfaceControl, based upon the size difference between the
// source (DisplayArea to capture) and output (surface the app reads images from).
- .setMatrix(mRecordedSurface, scale, 0 /* dtdx */, 0 /* dtdy */, scale)
+ .setMatrix(mRecordedSurface, scale.x, 0 /* dtdx */, 0 /* dtdy */, scale.y)
// Position needs to be updated when the mirrored DisplayArea has changed, since
// the content will no longer be centered in the output surface.
.setPosition(mRecordedSurface, shiftedX /* x */, shiftedY /* y */);
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 94e66ff..33ef3c5 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -45,7 +45,6 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.util.ArraySet;
import android.util.MathUtils;
import android.util.Slog;
@@ -117,8 +116,6 @@
private boolean mShouldOffsetWallpaperCenter;
- final boolean mIsLockscreenLiveWallpaperEnabled;
-
private final Consumer<WindowState> mFindWallpapers = w -> {
if (w.mAttrs.type == TYPE_WALLPAPER) {
WallpaperWindowToken token = w.mToken.asWallpaperToken();
@@ -236,9 +233,6 @@
WallpaperController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
mDisplayContent = displayContent;
- mIsLockscreenLiveWallpaperEnabled =
- SystemProperties.getBoolean("persist.wm.debug.lockscreen_live_wallpaper", true);
-
Resources resources = service.mContext.getResources();
mMinWallpaperScale =
resources.getFloat(com.android.internal.R.dimen.config_wallpaperMinScale);
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 1ed1431..15bd607 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -82,18 +82,16 @@
return;
}
mShowWhenLocked = showWhenLocked;
- if (mDisplayContent.mWallpaperController.mIsLockscreenLiveWallpaperEnabled) {
- // Move the window token to the front (private) or back (showWhenLocked). This is
- // possible
- // because the DisplayArea underneath TaskDisplayArea only contains TYPE_WALLPAPER
- // windows.
- final int position = showWhenLocked ? POSITION_BOTTOM : POSITION_TOP;
+ // Move the window token to the front (private) or back (showWhenLocked). This is
+ // possible
+ // because the DisplayArea underneath TaskDisplayArea only contains TYPE_WALLPAPER
+ // windows.
+ final int position = showWhenLocked ? POSITION_BOTTOM : POSITION_TOP;
- // Note: Moving all the way to the front or back breaks ordering based on addition
- // times.
- // We should never have more than one non-animating token of each type.
- getParent().positionChildAt(position, this /* child */, false /*includingParents */);
- }
+ // Note: Moving all the way to the front or back breaks ordering based on addition
+ // times.
+ // We should never have more than one non-animating token of each type.
+ getParent().positionChildAt(position, this /* child */, false /*includingParents */);
}
boolean canShowWhenLocked() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index eefe5af..3dbab13 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -462,7 +462,7 @@
wallpaper.wallpaperObserver.stopWatching();
spyOn(wallpaper.wallpaperObserver);
- doReturn(wallpaper).when(wallpaper.wallpaperObserver).dataForEvent(true, false);
+ doReturn(wallpaper).when(wallpaper.wallpaperObserver).dataForEvent(false);
wallpaper.wallpaperObserver.onEvent(CLOSE_WRITE, WALLPAPER);
// ACTION_WALLPAPER_CHANGED should be invoked before onWallpaperColorsChanged.
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index 6bfd93b..4bb7d63 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -4,6 +4,8 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static com.android.server.job.JobStore.JOB_FILE_SPLIT_PREFIX;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -46,6 +48,7 @@
import org.junit.runner.RunWith;
import java.io.File;
+import java.nio.file.Files;
import java.time.Clock;
import java.time.ZoneOffset;
import java.util.ArrayList;
@@ -209,6 +212,43 @@
assertEquals("Incorrect # of persisted tasks.", 0, jobStatusSet.size());
}
+ @Test
+ public void testSkipExtraFiles() throws Exception {
+ setUseSplitFiles(true);
+ final JobInfo task1 = new Builder(8, mComponent)
+ .setRequiresDeviceIdle(true)
+ .setPeriodic(10000L)
+ .setRequiresCharging(true)
+ .setPersisted(true)
+ .build();
+ final JobInfo task2 = new Builder(12, mComponent)
+ .setMinimumLatency(5000L)
+ .setBackoffCriteria(15000L, JobInfo.BACKOFF_POLICY_LINEAR)
+ .setOverrideDeadline(30000L)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
+ .setPersisted(true)
+ .build();
+ final int uid1 = SOME_UID;
+ final int uid2 = uid1 + 1;
+ final JobStatus JobStatus1 = JobStatus.createFromJobInfo(task1, uid1, null, -1, null, null);
+ final JobStatus JobStatus2 = JobStatus.createFromJobInfo(task2, uid2, null, -1, null, null);
+ runWritingJobsToDisk(JobStatus1, JobStatus2);
+
+ final File rootDir = new File(mTestContext.getFilesDir(), "system/job");
+ final File file1 = new File(rootDir, JOB_FILE_SPLIT_PREFIX + uid1 + ".xml");
+ final File file2 = new File(rootDir, JOB_FILE_SPLIT_PREFIX + uid2 + ".xml");
+
+ Files.copy(file1.toPath(),
+ new File(rootDir, JOB_FILE_SPLIT_PREFIX + uid1 + ".xml.bak").toPath());
+ Files.copy(file1.toPath(), new File(rootDir, "random.xml").toPath());
+ Files.copy(file2.toPath(),
+ new File(rootDir, "blah" + JOB_FILE_SPLIT_PREFIX + uid1 + ".xml").toPath());
+
+ JobSet jobStatusSet = new JobSet();
+ mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
+ assertEquals("Incorrect # of persisted tasks.", 2, jobStatusSet.size());
+ }
+
/**
* Test that dynamic constraints aren't written to disk.
*/
@@ -254,22 +294,22 @@
file = new File(mTestContext.getFilesDir(), "10000");
assertEquals(JobStore.INVALID_UID, JobStore.extractUidFromJobFileName(file));
- file = new File(mTestContext.getFilesDir(), JobStore.JOB_FILE_SPLIT_PREFIX);
+ file = new File(mTestContext.getFilesDir(), JOB_FILE_SPLIT_PREFIX);
assertEquals(JobStore.INVALID_UID, JobStore.extractUidFromJobFileName(file));
- file = new File(mTestContext.getFilesDir(), JobStore.JOB_FILE_SPLIT_PREFIX + "text.xml");
+ file = new File(mTestContext.getFilesDir(), JOB_FILE_SPLIT_PREFIX + "text.xml");
assertEquals(JobStore.INVALID_UID, JobStore.extractUidFromJobFileName(file));
- file = new File(mTestContext.getFilesDir(), JobStore.JOB_FILE_SPLIT_PREFIX + ".xml");
+ file = new File(mTestContext.getFilesDir(), JOB_FILE_SPLIT_PREFIX + ".xml");
assertEquals(JobStore.INVALID_UID, JobStore.extractUidFromJobFileName(file));
- file = new File(mTestContext.getFilesDir(), JobStore.JOB_FILE_SPLIT_PREFIX + "-10123.xml");
+ file = new File(mTestContext.getFilesDir(), JOB_FILE_SPLIT_PREFIX + "-10123.xml");
assertEquals(JobStore.INVALID_UID, JobStore.extractUidFromJobFileName(file));
- file = new File(mTestContext.getFilesDir(), JobStore.JOB_FILE_SPLIT_PREFIX + "1.xml");
+ file = new File(mTestContext.getFilesDir(), JOB_FILE_SPLIT_PREFIX + "1.xml");
assertEquals(1, JobStore.extractUidFromJobFileName(file));
- file = new File(mTestContext.getFilesDir(), JobStore.JOB_FILE_SPLIT_PREFIX + "101023.xml");
+ file = new File(mTestContext.getFilesDir(), JOB_FILE_SPLIT_PREFIX + "101023.xml");
assertEquals(101023, JobStore.extractUidFromJobFileName(file));
}
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index f94aff7..9f6d7f2 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -27,6 +27,7 @@
import static android.view.Display.INVALID_DISPLAY;
import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -39,6 +40,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
@@ -133,7 +135,7 @@
private final MediaProjectionManagerService.Injector mMediaProjectionMetricsLoggerInjector =
new MediaProjectionManagerService.Injector() {
@Override
- MediaProjectionMetricsLogger mediaProjectionMetricsLogger() {
+ MediaProjectionMetricsLogger mediaProjectionMetricsLogger(Context context) {
return mMediaProjectionMetricsLogger;
}
};
@@ -311,6 +313,70 @@
}
@Test
+ public void stop_noActiveProjections_doesNotLog() throws Exception {
+ MediaProjectionManagerService service =
+ new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+ MediaProjectionManagerService.MediaProjection projection =
+ startProjectionPreconditions(service);
+
+ projection.stop();
+
+ verifyZeroInteractions(mMediaProjectionMetricsLogger);
+ }
+
+ @Test
+ public void stop_noSession_logsHostUidAndUnknownTargetUid() throws Exception {
+ MediaProjectionManagerService service =
+ new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+ MediaProjectionManagerService.MediaProjection projection =
+ startProjectionPreconditions(service);
+ projection.start(mIMediaProjectionCallback);
+
+ projection.stop();
+
+ verify(mMediaProjectionMetricsLogger)
+ .logStopped(UID, ContentRecordingSession.TARGET_UID_UNKNOWN);
+ }
+
+ @Test
+ public void stop_displaySession_logsHostUidAndUnknownTargetUidFullScreen() throws Exception {
+ MediaProjectionManagerService service =
+ new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+ MediaProjectionManagerService.MediaProjection projection =
+ startProjectionPreconditions(service);
+ projection.start(mIMediaProjectionCallback);
+ doReturn(true)
+ .when(mWindowManagerInternal)
+ .setContentRecordingSession(any(ContentRecordingSession.class));
+ service.setContentRecordingSession(DISPLAY_SESSION);
+
+ projection.stop();
+
+ verify(mMediaProjectionMetricsLogger)
+ .logStopped(UID, ContentRecordingSession.TARGET_UID_FULL_SCREEN);
+ }
+
+ @Test
+ public void stop_taskSession_logsHostUidAndTargetUid() throws Exception {
+ int targetUid = 1234;
+ MediaProjectionManagerService service =
+ new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+ MediaProjectionManagerService.MediaProjection projection =
+ startProjectionPreconditions(service);
+ projection.start(mIMediaProjectionCallback);
+ doReturn(true)
+ .when(mWindowManagerInternal)
+ .setContentRecordingSession(any(ContentRecordingSession.class));
+ ContentRecordingSession taskSession =
+ ContentRecordingSession.createTaskSession(mock(IBinder.class), targetUid);
+ service.setContentRecordingSession(taskSession);
+
+ projection.stop();
+
+ verify(mMediaProjectionMetricsLogger).logStopped(UID, targetUid);
+ }
+
+ @Test
public void testIsValid_multipleStarts_preventionDisabled() throws NameNotFoundException {
MediaProjectionManagerService service = new MediaProjectionManagerService(mContext,
mPreventReusedTokenDisabledInjector);
@@ -586,6 +652,18 @@
/* isSetSessionSuccessful= */ false, RECORD_CANCEL);
}
+ @Test
+ public void notifyPermissionRequestInitiated_forwardsToLogger() {
+ int hostUid = 123;
+ int sessionCreationSource = 456;
+ mService =
+ new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+
+ mService.notifyPermissionRequestInitiated(hostUid, sessionCreationSource);
+
+ verify(mMediaProjectionMetricsLogger).logInitiated(hostUid, sessionCreationSource);
+ }
+
/**
* Executes and validates scenario where the consent result indicates the projection ends.
*/
@@ -749,8 +827,10 @@
public void setContentRecordingSession_success_logsCaptureInProgress()
throws Exception {
mService.addCallback(mWatcherCallback);
- MediaProjectionManagerService service = new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
- MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
+ MediaProjectionManagerService service =
+ new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+ MediaProjectionManagerService.MediaProjection projection =
+ startProjectionPreconditions(service);
projection.start(mIMediaProjectionCallback);
doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
any(ContentRecordingSession.class));
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
new file mode 100644
index 0000000..73b4cc8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media.projection;
+
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.time.Duration;
+
+/**
+ * Tests for the {@link MediaProjectionMetricsLoggerTest} class.
+ *
+ * <p>Build/Install/Run: atest FrameworksServicesTests:MediaProjectionMetricsLoggerTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class MediaProjectionMetricsLoggerTest {
+
+ private static final int TEST_HOST_UID = 123;
+ private static final int TEST_TARGET_UID = 456;
+ private static final int TEST_CREATION_SOURCE = 789;
+
+ @Mock private FrameworkStatsLogWrapper mFrameworkStatsLogWrapper;
+ @Mock private MediaProjectionSessionIdGenerator mSessionIdGenerator;
+ @Mock private MediaProjectionTimestampStore mTimestampStore;
+
+ private MediaProjectionMetricsLogger mLogger;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mLogger =
+ new MediaProjectionMetricsLogger(
+ mFrameworkStatsLogWrapper, mSessionIdGenerator, mTimestampStore);
+ }
+
+ @Test
+ public void logInitiated_logsStateChangedAtomId() {
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+
+ verifyStateChangedAtomIdLogged();
+ }
+
+ @Test
+ public void logInitiated_logsStateInitiated() {
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+
+ verifyStateLogged(MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
+ }
+
+ @Test
+ public void logInitiated_logsHostUid() {
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+
+ verifyHostUidLogged(TEST_HOST_UID);
+ }
+
+ @Test
+ public void logInitiated_logsSessionCreationSource() {
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+
+ verifyCreationSourceLogged(TEST_CREATION_SOURCE);
+ }
+
+ @Test
+ public void logInitiated_logsUnknownTargetUid() {
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+
+ verifyTargetUidLogged(-2);
+ }
+
+ @Test
+ public void logInitiated_noPreviousSession_logsUnknownTimeSinceLastActive() {
+ when(mTimestampStore.timeSinceLastActiveSession()).thenReturn(null);
+
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+
+ verifyTimeSinceLastActiveSessionLogged(-1);
+ }
+
+ @Test
+ public void logInitiated_previousSession_logsTimeSinceLastActiveInSeconds() {
+ Duration timeSinceLastActiveSession = Duration.ofHours(1234);
+ when(mTimestampStore.timeSinceLastActiveSession()).thenReturn(timeSinceLastActiveSession);
+
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+
+ verifyTimeSinceLastActiveSessionLogged((int) timeSinceLastActiveSession.toSeconds());
+ }
+
+ @Test
+ public void logInitiated_logsNewSessionId() {
+ int newSessionId = 123;
+ when(mSessionIdGenerator.createAndGetNewSessionId()).thenReturn(newSessionId);
+
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+
+ verifySessionIdLogged(newSessionId);
+ }
+
+ @Test
+ public void logInitiated_logsPreviousState() {
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ verifyPreviousStateLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN);
+
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ verifyPreviousStateLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
+ }
+
+ @Test
+ public void logStopped_logsStateChangedAtomId() {
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+
+ verifyStateChangedAtomIdLogged();
+ }
+
+ @Test
+ public void logStopped_logsCurrentSessionId() {
+ int currentSessionId = 987;
+ when(mSessionIdGenerator.getCurrentSessionId()).thenReturn(currentSessionId);
+
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+
+ verifySessionIdLogged(currentSessionId);
+ }
+
+ @Test
+ public void logStopped_logsStateStopped() {
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+
+ verifyStateLogged(MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED);
+ }
+
+ @Test
+ public void logStopped_logsHostUid() {
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+
+ verifyHostUidLogged(TEST_HOST_UID);
+ }
+
+ @Test
+ public void logStopped_logsTargetUid() {
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+
+ verifyTargetUidLogged(TEST_TARGET_UID);
+ }
+
+ @Test
+ public void logStopped_logsUnknownTimeSinceLastActive() {
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+
+ verifyTimeSinceLastActiveSessionLogged(-1);
+ }
+
+ @Test
+ public void logStopped_logsUnknownSessionCreationSource() {
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+
+ verifyCreationSourceLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+ }
+
+ @Test
+ public void logStopped_logsPreviousState() {
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+ verifyPreviousStateLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN);
+
+ mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ verifyPreviousStateLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED);
+
+ mLogger.logStopped(TEST_HOST_UID, TEST_CREATION_SOURCE);
+ verifyPreviousStateLogged(
+ MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
+ }
+
+ @Test
+ public void logStopped_registersActiveSessionEnded_afterLogging() {
+ mLogger.logStopped(TEST_HOST_UID, TEST_TARGET_UID);
+
+ InOrder inOrder = inOrder(mFrameworkStatsLogWrapper, mTimestampStore);
+ inOrder.verify(mFrameworkStatsLogWrapper)
+ .write(
+ /* code= */ anyInt(),
+ /* sessionId= */ anyInt(),
+ /* state= */ anyInt(),
+ /* previousState= */ anyInt(),
+ /* hostUid= */ anyInt(),
+ /* targetUid= */ anyInt(),
+ /* timeSinceLastActive= */ anyInt(),
+ /* creationSource= */ anyInt());
+ inOrder.verify(mTimestampStore).registerActiveSessionEnded();
+ }
+
+ private void verifyStateChangedAtomIdLogged() {
+ verify(mFrameworkStatsLogWrapper)
+ .write(
+ /* code= */ eq(FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED),
+ /* sessionId= */ anyInt(),
+ /* state= */ anyInt(),
+ /* previousState= */ anyInt(),
+ /* hostUid= */ anyInt(),
+ /* targetUid= */ anyInt(),
+ /* timeSinceLastActive= */ anyInt(),
+ /* creationSource= */ anyInt());
+ }
+
+ private void verifyStateLogged(int state) {
+ verify(mFrameworkStatsLogWrapper)
+ .write(
+ /* code= */ anyInt(),
+ /* sessionId= */ anyInt(),
+ eq(state),
+ /* previousState= */ anyInt(),
+ /* hostUid= */ anyInt(),
+ /* targetUid= */ anyInt(),
+ /* timeSinceLastActive= */ anyInt(),
+ /* creationSource= */ anyInt());
+ }
+
+ private void verifyHostUidLogged(int hostUid) {
+ verify(mFrameworkStatsLogWrapper)
+ .write(
+ /* code= */ anyInt(),
+ /* sessionId= */ anyInt(),
+ /* state= */ anyInt(),
+ /* previousState= */ anyInt(),
+ eq(hostUid),
+ /* targetUid= */ anyInt(),
+ /* timeSinceLastActive= */ anyInt(),
+ /* creationSource= */ anyInt());
+ }
+
+ private void verifyCreationSourceLogged(int creationSource) {
+ verify(mFrameworkStatsLogWrapper)
+ .write(
+ /* code= */ anyInt(),
+ /* sessionId= */ anyInt(),
+ /* state= */ anyInt(),
+ /* previousState= */ anyInt(),
+ /* hostUid= */ anyInt(),
+ /* targetUid= */ anyInt(),
+ /* timeSinceLastActive= */ anyInt(),
+ eq(creationSource));
+ }
+
+ private void verifyTargetUidLogged(int targetUid) {
+ verify(mFrameworkStatsLogWrapper)
+ .write(
+ /* code= */ anyInt(),
+ /* sessionId= */ anyInt(),
+ /* state= */ anyInt(),
+ /* previousState= */ anyInt(),
+ /* hostUid= */ anyInt(),
+ eq(targetUid),
+ /* timeSinceLastActive= */ anyInt(),
+ /* creationSource= */ anyInt());
+ }
+
+ private void verifyTimeSinceLastActiveSessionLogged(int timeSinceLastActiveSession) {
+ verify(mFrameworkStatsLogWrapper)
+ .write(
+ /* code= */ anyInt(),
+ /* sessionId= */ anyInt(),
+ /* state= */ anyInt(),
+ /* previousState= */ anyInt(),
+ /* hostUid= */ anyInt(),
+ /* targetUid= */ anyInt(),
+ /* timeSinceLastActive= */ eq(timeSinceLastActiveSession),
+ /* creationSource= */ anyInt());
+ }
+
+ private void verifySessionIdLogged(int newSessionId) {
+ verify(mFrameworkStatsLogWrapper)
+ .write(
+ /* code= */ anyInt(),
+ /* sessionId= */ eq(newSessionId),
+ /* state= */ anyInt(),
+ /* previousState= */ anyInt(),
+ /* hostUid= */ anyInt(),
+ /* targetUid= */ anyInt(),
+ /* timeSinceLastActive= */ anyInt(),
+ /* creationSource= */ anyInt());
+ }
+
+ private void verifyPreviousStateLogged(int previousState) {
+ verify(mFrameworkStatsLogWrapper)
+ .write(
+ /* code= */ anyInt(),
+ /* sessionId= */ anyInt(),
+ /* state= */ anyInt(),
+ eq(previousState),
+ /* hostUid= */ anyInt(),
+ /* targetUid= */ anyInt(),
+ /* timeSinceLastActive= */ anyInt(),
+ /* creationSource= */ anyInt());
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
index 9bd938f..cf8548c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
@@ -80,7 +80,9 @@
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
+
import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
import com.android.internal.config.sysui.TestableFlagResolver;
import com.android.internal.logging.InstanceIdSequence;
@@ -93,6 +95,7 @@
import java.util.List;
import java.util.Objects;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -190,7 +193,7 @@
assertTrue(mAccessibilityManager.isEnabled());
// TODO (b/291907312): remove feature flag
- mTestFlagResolver.setFlagOverride(NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR, true);
+ mSetFlagsRule.enableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER);
// Disable feature flags by default. Tests should enable as needed.
mSetFlagsRule.disableFlags(Flags.FLAG_POLITE_NOTIFICATIONS, Flags.FLAG_EXPIRE_BITMAPS);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 75d012a..6792cfe 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -71,6 +71,7 @@
import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
+import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
@@ -84,7 +85,6 @@
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.ENABLE_ATTENTION_HELPER_REFACTOR;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.FSI_FORCE_DEMOTE;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
@@ -207,6 +207,7 @@
import android.os.UserManager;
import android.os.WorkSource;
import android.permission.PermissionManager;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
@@ -318,6 +319,7 @@
private static final int UID_HEADLESS = 1_000_000;
private static final int TOAST_DURATION = 2_000;
private static final int SECONDARY_DISPLAY_ID = 42;
+ private static final int TEST_PROFILE_USERHANDLE = 12;
private final int mUid = Binder.getCallingUid();
private final @UserIdInt int mUserId = UserHandle.getUserId(mUid);
@@ -445,7 +447,7 @@
TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
TestableFlagResolver mTestFlagResolver = new TestableFlagResolver();
-
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30);
@Mock
@@ -611,7 +613,8 @@
});
// TODO (b/291907312): remove feature flag
- mTestFlagResolver.setFlagOverride(ENABLE_ATTENTION_HELPER_REFACTOR, false);
+ mSetFlagsRule.disableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER,
+ Flags.FLAG_POLITE_NOTIFICATIONS);
initNMS();
}
@@ -652,7 +655,7 @@
verify(mHistoryManager).onBootPhaseAppsCanStart();
// TODO b/291907312: remove feature flag
- if (mTestFlagResolver.isEnabled(ENABLE_ATTENTION_HELPER_REFACTOR)) {
+ if (Flags.refactorAttentionHelper()) {
mService.mAttentionHelper.setAudioManager(mAudioManager);
} else {
mService.setAudioManager(mAudioManager);
@@ -826,6 +829,12 @@
mPackageIntentReceiver.onReceive(getContext(), intent);
}
+ private void simulateProfileAvailabilityActions(String intentAction) {
+ final Intent intent = new Intent(intentAction);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, TEST_PROFILE_USERHANDLE);
+ mUserSwitchIntentReceiver.onReceive(mContext, intent);
+ }
+
private ArrayMap<Boolean, ArrayList<ComponentName>> generateResetComponentValues() {
ArrayMap<Boolean, ArrayList<ComponentName>> changed = new ArrayMap<>();
changed.put(true, new ArrayList<>());
@@ -1683,7 +1692,7 @@
@Test
public void testEnqueueNotificationWithTag_WritesExpectedLogs_NAHRefactor() throws Exception {
// TODO b/291907312: remove feature flag
- mTestFlagResolver.setFlagOverride(ENABLE_ATTENTION_HELPER_REFACTOR, true);
+ mSetFlagsRule.enableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER);
// Cleanup NMS before re-initializing
if (mService != null) {
try {
@@ -9146,7 +9155,7 @@
public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped_NAHRefactor()
throws Exception {
// TODO b/291907312: remove feature flag
- mTestFlagResolver.setFlagOverride(ENABLE_ATTENTION_HELPER_REFACTOR, true);
+ mSetFlagsRule.enableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER);
// Cleanup NMS before re-initializing
if (mService != null) {
try {
@@ -12751,6 +12760,23 @@
verify(service, times(1)).setDNDMigrationDone(user.id);
}
+ @Test
+ public void testProfileUnavailableIntent() throws RemoteException {
+ mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
+ simulateProfileAvailabilityActions(Intent.ACTION_PROFILE_UNAVAILABLE);
+ verify(mWorkerHandler).post(any(Runnable.class));
+ verify(mSnoozeHelper).clearData(anyInt());
+ }
+
+
+ @Test
+ public void testManagedProfileUnavailableIntent() throws RemoteException {
+ mSetFlagsRule.disableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
+ simulateProfileAvailabilityActions(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ verify(mWorkerHandler).post(any(Runnable.class));
+ verify(mSnoozeHelper).clearData(anyInt());
+ }
+
private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName)
throws RemoteException {
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, testName, mUid, 0,
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index af39b2f..1b8d746 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -60,6 +60,7 @@
"truth",
"testables",
"hamcrest-library",
+ "flag-junit",
"platform-compat-test-rules",
"CtsSurfaceValidatorLib",
"service-sdksandbox.impl",
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index 8db09f9..61c4d06 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -46,7 +46,6 @@
import static java.util.Collections.unmodifiableMap;
import android.content.Context;
-import android.os.Looper;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.view.InputDevice;
@@ -99,10 +98,6 @@
* settings values.
*/
protected final void setUpPhoneWindowManager(boolean supportSettingsUpdate) {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
doReturn(mSettingsProviderRule.mockContentResolver(mContext))
.when(mContext).getContentResolver();
mPhoneWindowManager = new TestPhoneWindowManager(mContext, supportSettingsUpdate);
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 2244dbe..261d3cc 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -78,6 +78,7 @@
import android.os.UserHandle;
import android.os.Vibrator;
import android.os.VibratorInfo;
+import android.os.test.TestLooper;
import android.service.dreams.DreamManagerInternal;
import android.telecom.TelecomManager;
import android.util.FeatureFlagUtils;
@@ -160,12 +161,13 @@
@Mock private KeyguardServiceDelegate mKeyguardServiceDelegate;
private StaticMockitoSession mMockitoSession;
+ private TestLooper mTestLooper = new TestLooper();
private HandlerThread mHandlerThread;
private Handler mHandler;
private class TestInjector extends PhoneWindowManager.Injector {
TestInjector(Context context, WindowManagerPolicy.WindowManagerFuncs funcs) {
- super(context, funcs);
+ super(context, funcs, mTestLooper.getLooper());
}
AccessibilityShortcutController getAccessibilityShortcutController(
@@ -184,12 +186,10 @@
TestPhoneWindowManager(Context context, boolean supportSettingsUpdate) {
MockitoAnnotations.initMocks(this);
- mHandlerThread = new HandlerThread("fake window manager");
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
+ mHandler = new Handler(mTestLooper.getLooper());
mContext = mockingDetails(context).isSpy() ? context : spy(context);
- mHandler.runWithScissors(() -> setUp(supportSettingsUpdate), 0 /* timeout */);
- waitForIdle();
+ mHandler.post(() -> setUp(supportSettingsUpdate));
+ mTestLooper.dispatchAll();
}
private void setUp(boolean supportSettingsUpdate) {
@@ -301,7 +301,6 @@
}
void tearDown() {
- mHandlerThread.quitSafely();
LocalServices.removeServiceForTest(InputMethodManagerInternal.class);
Mockito.reset(mPhoneWindowManager);
mMockitoSession.finishMocking();
@@ -327,10 +326,6 @@
mPhoneWindowManager.dispatchUnhandledKey(null /*focusedToken*/, event, FLAG_INTERACTIVE);
}
- void waitForIdle() {
- mHandler.runWithScissors(() -> { }, 0 /* timeout */);
- }
-
/**
* Below functions will override the setting or the policy behavior.
*/
@@ -504,13 +499,13 @@
* Below functions will check the policy behavior could be invoked.
*/
void assertTakeScreenshotCalled() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mDisplayPolicy, timeout(SHORTCUT_KEY_DELAY_MILLIS))
.takeScreenshot(anyInt(), anyInt());
}
void assertShowGlobalActionsCalled() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mPhoneWindowManager).showGlobalActions();
verify(mGlobalActions, timeout(SHORTCUT_KEY_DELAY_MILLIS))
.showDialog(anyBoolean(), anyBoolean());
@@ -519,53 +514,53 @@
}
void assertVolumeMute() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mAudioManagerInternal, timeout(SHORTCUT_KEY_DELAY_MILLIS))
.silenceRingerModeInternal(eq("volume_hush"));
}
void assertAccessibilityKeychordCalled() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mAccessibilityShortcutController,
timeout(SHORTCUT_KEY_DELAY_MILLIS)).performAccessibilityShortcut();
}
void assertDreamRequest() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mDreamManagerInternal).requestDream();
}
void assertPowerSleep() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mPowerManager,
timeout(SHORTCUT_KEY_DELAY_MILLIS)).goToSleep(anyLong(), anyInt(), anyInt());
}
void assertPowerWakeUp() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mPowerManager,
timeout(SHORTCUT_KEY_DELAY_MILLIS)).wakeUp(anyLong(), anyInt(), anyString());
}
void assertNoPowerSleep() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mPowerManager, never()).goToSleep(anyLong(), anyInt(), anyInt());
}
void assertCameraLaunch() {
- waitForIdle();
+ mTestLooper.dispatchAll();
// GestureLauncherService should receive interceptPowerKeyDown twice.
verify(mGestureLauncherService, times(2))
.interceptPowerKeyDown(any(), anyBoolean(), any());
}
void assertSearchManagerLaunchAssist() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mSearchManager, timeout(SHORTCUT_KEY_DELAY_MILLIS)).launchAssist(any());
}
void assertLaunchCategory(String category) {
- waitForIdle();
+ mTestLooper.dispatchAll();
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
try {
verify(mContext).startActivityAsUser(intentCaptor.capture(), any());
@@ -578,17 +573,17 @@
}
void assertShowRecentApps() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mStatusBarManagerInternal).showRecentApps(anyBoolean());
}
void assertStatusBarStartAssist() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mStatusBarManagerInternal).startAssist(any());
}
void assertSwitchKeyboardLayout(int direction) {
- waitForIdle();
+ mTestLooper.dispatchAll();
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)) {
verify(mInputMethodManagerInternal).switchKeyboardLayout(eq(direction));
verify(mWindowManagerFuncsImpl, never()).switchKeyboardLayout(anyInt(), anyInt());
@@ -599,7 +594,7 @@
}
void assertTakeBugreport() {
- waitForIdle();
+ mTestLooper.dispatchAll();
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mContext).sendOrderedBroadcastAsUser(intentCaptor.capture(), any(), any(), any(),
any(), anyInt(), any(), any());
@@ -607,17 +602,17 @@
}
void assertTogglePanel() throws RemoteException {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mPhoneWindowManager.mStatusBarService).togglePanel();
}
void assertToggleShortcutsMenu() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mStatusBarManagerInternal).toggleKeyboardShortcutsMenu(anyInt());
}
void assertToggleCapsLock() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mInputManagerInternal).toggleCapsLock(anyInt());
}
@@ -642,12 +637,12 @@
}
void assertGoToHomescreen() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mPhoneWindowManager).launchHomeFromHotKey(anyInt());
}
void assertOpenAllAppView() {
- waitForIdle();
+ mTestLooper.dispatchAll();
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mContext, timeout(TEST_SINGLE_KEY_DELAY_MILLIS))
.startActivityAsUser(intentCaptor.capture(), isNull(), any(UserHandle.class));
@@ -655,13 +650,13 @@
}
void assertNotOpenAllAppView() {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(mContext, after(TEST_SINGLE_KEY_DELAY_MILLIS).never())
.startActivityAsUser(any(Intent.class), any(), any(UserHandle.class));
}
void assertActivityTargetLaunched(ComponentName targetActivity) {
- waitForIdle();
+ mTestLooper.dispatchAll();
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mContext, timeout(TEST_SINGLE_KEY_DELAY_MILLIS))
.startActivityAsUser(intentCaptor.capture(), isNull(), any(UserHandle.class));
@@ -670,7 +665,7 @@
void assertShortcutLogged(int vendorId, int productId, KeyboardLogEvent logEvent,
int expectedKey, int expectedModifierState, String errorMsg) {
- waitForIdle();
+ mTestLooper.dispatchAll();
verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED,
vendorId, productId, logEvent.getIntValue(), new int[]{expectedKey},
expectedModifierState), description(errorMsg));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index d2eb1cc..78566fb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -84,31 +84,49 @@
private final ContentRecordingSession mWaitingDisplaySession =
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
private ContentRecordingSession mTaskSession;
- private static Point sSurfaceSize;
+ private Point mSurfaceSize;
private ContentRecorder mContentRecorder;
@Mock private MediaProjectionManagerWrapper mMediaProjectionManagerWrapper;
private SurfaceControl mRecordedSurface;
+ private boolean mHandleAnisotropicDisplayMirroring = false;
+
@Before public void setUp() {
MockitoAnnotations.initMocks(this);
- // GIVEN SurfaceControl can successfully mirror the provided surface.
- sSurfaceSize = new Point(
- mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
- mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
- mRecordedSurface = surfaceControlMirrors(sSurfaceSize);
-
doReturn(INVALID_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt());
- // GIVEN the VirtualDisplay associated with the session (so the display has state ON).
+ // Skip unnecessary operations of relayout.
+ spyOn(mWm.mWindowPlacerLocked);
+ doNothing().when(mWm.mWindowPlacerLocked).performSurfacePlacement(anyBoolean());
+ }
+
+ private void defaultInit() {
+ createContentRecorder(createDefaultDisplayInfo());
+ }
+
+ private DisplayInfo createDefaultDisplayInfo() {
+ return createDisplayInfo(mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
+ mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
+ }
+
+ private DisplayInfo createDisplayInfo(int width, int height) {
+ // GIVEN SurfaceControl can successfully mirror the provided surface.
+ mSurfaceSize = new Point(width, height);
+ mRecordedSurface = surfaceControlMirrors(mSurfaceSize);
+
DisplayInfo displayInfo = mDisplayInfo;
- displayInfo.logicalWidth = sSurfaceSize.x;
- displayInfo.logicalHeight = sSurfaceSize.y;
+ displayInfo.logicalWidth = width;
+ displayInfo.logicalHeight = height;
displayInfo.state = STATE_ON;
+ return displayInfo;
+ }
+
+ private void createContentRecorder(DisplayInfo displayInfo) {
mVirtualDisplayContent = createNewDisplay(displayInfo);
final int displayId = mVirtualDisplayContent.getDisplayId();
mContentRecorder = new ContentRecorder(mVirtualDisplayContent,
- mMediaProjectionManagerWrapper);
+ mMediaProjectionManagerWrapper, mHandleAnisotropicDisplayMirroring);
spyOn(mVirtualDisplayContent);
// GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
@@ -124,14 +142,11 @@
// GIVEN a session is waiting for the user to review consent.
mWaitingDisplaySession.setVirtualDisplayId(displayId);
mWaitingDisplaySession.setWaitingForConsent(true);
-
- // Skip unnecessary operations of relayout.
- spyOn(mWm.mWindowPlacerLocked);
- doNothing().when(mWm.mWindowPlacerLocked).performSurfacePlacement(anyBoolean());
}
@Test
public void testIsCurrentlyRecording() {
+ defaultInit();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
mContentRecorder.updateRecording();
@@ -140,6 +155,7 @@
@Test
public void testUpdateRecording_display() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
@@ -147,6 +163,7 @@
@Test
public void testUpdateRecording_display_invalidDisplayIdToMirror() {
+ defaultInit();
ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
INVALID_DISPLAY);
mContentRecorder.setContentRecordingSession(session);
@@ -156,6 +173,7 @@
@Test
public void testUpdateRecording_display_noDisplayContentToMirror() {
+ defaultInit();
doReturn(null).when(
mWm.mRoot).getDisplayContent(anyInt());
mContentRecorder.setContentRecordingSession(mDisplaySession);
@@ -165,6 +183,7 @@
@Test
public void testUpdateRecording_task_nullToken() {
+ defaultInit();
ContentRecordingSession session = mTaskSession;
session.setVirtualDisplayId(mDisplaySession.getVirtualDisplayId());
session.setTokenToRecord(null);
@@ -176,6 +195,7 @@
@Test
public void testUpdateRecording_task_noWindowContainer() {
+ defaultInit();
// Use the window container token of the DisplayContent, rather than task.
ContentRecordingSession invalidTaskSession = ContentRecordingSession.createTaskSession(
new WindowContainer.RemoteToken(mDisplayContent));
@@ -187,6 +207,7 @@
@Test
public void testUpdateRecording_wasPaused() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
@@ -197,6 +218,7 @@
@Test
public void testUpdateRecording_waitingForConsent() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mWaitingDisplaySession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
@@ -209,6 +231,7 @@
@Test
public void testOnConfigurationChanged_neverRecording() {
+ defaultInit();
mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
verify(mTransaction, never()).setPosition(eq(mRecordedSurface), anyFloat(), anyFloat());
@@ -218,6 +241,7 @@
@Test
public void testOnConfigurationChanged_resizesSurface() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
// Ensure a different orientation when we check if something has changed.
@@ -234,13 +258,14 @@
@Test
public void testOnConfigurationChanged_resizesVirtualDisplay() {
+ defaultInit();
final int newWidth = 55;
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
// The user rotates the device, so the host app resizes the virtual display for the capture.
- resizeDisplay(mDisplayContent, newWidth, sSurfaceSize.y);
- resizeDisplay(mVirtualDisplayContent, newWidth, sSurfaceSize.y);
+ resizeDisplay(mDisplayContent, newWidth, mSurfaceSize.y);
+ resizeDisplay(mVirtualDisplayContent, newWidth, mSurfaceSize.y);
mContentRecorder.onConfigurationChanged(mDisplayContent.getConfiguration().orientation);
verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
@@ -251,6 +276,7 @@
@Test
public void testOnConfigurationChanged_rotateVirtualDisplay() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
@@ -271,12 +297,13 @@
*/
@Test
public void testOnConfigurationChanged_resizeSurface() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
// Resize the output surface.
- final Point newSurfaceSize = new Point(Math.round(sSurfaceSize.x / 2f),
- Math.round(sSurfaceSize.y * 2));
+ final Point newSurfaceSize = new Point(Math.round(mSurfaceSize.x / 2f),
+ Math.round(mSurfaceSize.y * 2));
doReturn(newSurfaceSize).when(mWm.mDisplayManagerInternal).getDisplaySurfaceDefaultSize(
anyInt());
mContentRecorder.onConfigurationChanged(
@@ -292,6 +319,7 @@
@Test
public void testOnTaskOrientationConfigurationChanged_resizesSurface() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
@@ -314,6 +342,7 @@
@Test
public void testOnTaskBoundsConfigurationChanged_notifiesCallback() {
+ defaultInit();
mTask.getRootTask().setWindowingMode(WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
final int minWidth = 222;
@@ -351,6 +380,7 @@
@Test
public void testTaskWindowingModeChanged_pip_stopsRecording() {
+ defaultInit();
// WHEN a recording is ongoing.
mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
mContentRecorder.setContentRecordingSession(mTaskSession);
@@ -368,6 +398,7 @@
@Test
public void testTaskWindowingModeChanged_fullscreen_startsRecording() {
+ defaultInit();
// WHEN a recording is ongoing.
mTask.setWindowingMode(WINDOWING_MODE_PINNED);
mContentRecorder.setContentRecordingSession(mTaskSession);
@@ -384,6 +415,7 @@
@Test
public void testStartRecording_notifiesCallback_taskSession() {
+ defaultInit();
// WHEN a recording is ongoing.
mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
@@ -396,6 +428,7 @@
@Test
public void testStartRecording_notifiesCallback_displaySession() {
+ defaultInit();
// WHEN a recording is ongoing.
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
@@ -408,6 +441,7 @@
@Test
public void testStartRecording_taskInPIP_recordingNotStarted() {
+ defaultInit();
// GIVEN a task is in PIP.
mContentRecorder.setContentRecordingSession(mTaskSession);
mTask.setWindowingMode(WINDOWING_MODE_PINNED);
@@ -421,6 +455,7 @@
@Test
public void testStartRecording_taskInSplit_recordingStarted() {
+ defaultInit();
// GIVEN a task is in PIP.
mContentRecorder.setContentRecordingSession(mTaskSession);
mTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
@@ -434,6 +469,7 @@
@Test
public void testStartRecording_taskInFullscreen_recordingStarted() {
+ defaultInit();
// GIVEN a task is in PIP.
mContentRecorder.setContentRecordingSession(mTaskSession);
mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
@@ -447,6 +483,7 @@
@Test
public void testOnVisibleRequestedChanged_notifiesCallback() {
+ defaultInit();
// WHEN a recording is ongoing.
mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
@@ -471,6 +508,7 @@
@Test
public void testOnVisibleRequestedChanged_noRecording_doesNotNotifyCallback() {
+ defaultInit();
// WHEN a recording is not ongoing.
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
@@ -493,6 +531,7 @@
@Test
public void testPauseRecording_pausesRecording() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
@@ -502,12 +541,14 @@
@Test
public void testPauseRecording_neverRecording() {
+ defaultInit();
mContentRecorder.pauseRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
}
@Test
public void testStopRecording_stopsRecording() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
@@ -517,12 +558,14 @@
@Test
public void testStopRecording_neverRecording() {
+ defaultInit();
mContentRecorder.stopRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
}
@Test
public void testRemoveTask_stopsRecording() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
@@ -533,6 +576,7 @@
@Test
public void testRemoveTask_stopsRecording_nullSessionShouldNotThrowExceptions() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
mContentRecorder.setContentRecordingSession(null);
@@ -541,6 +585,7 @@
@Test
public void testUpdateMirroredSurface_capturedAreaResized() {
+ defaultInit();
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
@@ -548,9 +593,9 @@
// WHEN attempting to mirror on the virtual display, and the captured content is resized.
float xScale = 0.7f;
float yScale = 2f;
- Rect displayAreaBounds = new Rect(0, 0, Math.round(sSurfaceSize.x * xScale),
- Math.round(sSurfaceSize.y * yScale));
- mContentRecorder.updateMirroredSurface(mTransaction, displayAreaBounds, sSurfaceSize);
+ Rect displayAreaBounds = new Rect(0, 0, Math.round(mSurfaceSize.x * xScale),
+ Math.round(mSurfaceSize.y * yScale));
+ mContentRecorder.updateMirroredSurface(mTransaction, displayAreaBounds, mSurfaceSize);
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
// THEN content in the captured DisplayArea is scaled to fit the surface size.
@@ -558,7 +603,7 @@
1.0f / yScale);
// THEN captured content is positioned in the centre of the output surface.
int scaledWidth = Math.round((float) displayAreaBounds.width() / xScale);
- int xInset = (sSurfaceSize.x - scaledWidth) / 2;
+ int xInset = (mSurfaceSize.x - scaledWidth) / 2;
verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0);
// THEN the resize callback is notified.
verify(mMediaProjectionManagerWrapper).notifyActiveProjectionCapturedContentResized(
@@ -566,7 +611,131 @@
}
@Test
+ public void testUpdateMirroredSurface_isotropicPixel() {
+ mHandleAnisotropicDisplayMirroring = false;
+ DisplayInfo displayInfo = createDefaultDisplayInfo();
+ createContentRecorder(displayInfo);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+
+ verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, 1, 0, 0, 1);
+ }
+
+ @Test
+ public void testUpdateMirroredSurface_anisotropicPixel_compressY() {
+ mHandleAnisotropicDisplayMirroring = true;
+ DisplayInfo displayInfo = createDefaultDisplayInfo();
+ DisplayInfo inputDisplayInfo =
+ mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY).getDisplayInfo();
+ displayInfo.physicalXDpi = 2.0f * inputDisplayInfo.physicalXDpi;
+ displayInfo.physicalYDpi = inputDisplayInfo.physicalYDpi;
+ createContentRecorder(displayInfo);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+
+ float xScale = 1f;
+ float yScale = 0.5f;
+ verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, xScale, 0, 0,
+ yScale);
+ verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, 0,
+ Math.round(0.25 * mSurfaceSize.y));
+ }
+
+ @Test
+ public void testUpdateMirroredSurface_anisotropicPixel_compressX() {
+ mHandleAnisotropicDisplayMirroring = true;
+ DisplayInfo displayInfo = createDefaultDisplayInfo();
+ DisplayInfo inputDisplayInfo =
+ mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY).getDisplayInfo();
+ displayInfo.physicalXDpi = inputDisplayInfo.physicalXDpi;
+ displayInfo.physicalYDpi = 2.0f * inputDisplayInfo.physicalYDpi;
+ createContentRecorder(displayInfo);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+
+ float xScale = 0.5f;
+ float yScale = 1f;
+ verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, xScale, 0, 0,
+ yScale);
+ verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface,
+ Math.round(0.25 * mSurfaceSize.x), 0);
+ }
+
+ @Test
+ public void testUpdateMirroredSurface_anisotropicPixel_scaleOnX() {
+ mHandleAnisotropicDisplayMirroring = true;
+ int width = 2 * mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width();
+ int height = 6 * mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height();
+ DisplayInfo displayInfo = createDisplayInfo(width, height);
+ DisplayInfo inputDisplayInfo =
+ mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY).getDisplayInfo();
+ displayInfo.physicalXDpi = inputDisplayInfo.physicalXDpi;
+ displayInfo.physicalYDpi = 2.0f * inputDisplayInfo.physicalYDpi;
+ createContentRecorder(displayInfo);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+
+ float xScale = 2f;
+ float yScale = 4f;
+ verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, xScale, 0, 0,
+ yScale);
+ verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, 0,
+ inputDisplayInfo.logicalHeight);
+ }
+
+ @Test
+ public void testUpdateMirroredSurface_anisotropicPixel_scaleOnY() {
+ mHandleAnisotropicDisplayMirroring = true;
+ int width = 6 * mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width();
+ int height = 2 * mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height();
+ DisplayInfo displayInfo = createDisplayInfo(width, height);
+ DisplayInfo inputDisplayInfo =
+ mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY).getDisplayInfo();
+ displayInfo.physicalXDpi = 2.0f * inputDisplayInfo.physicalXDpi;
+ displayInfo.physicalYDpi = inputDisplayInfo.physicalYDpi;
+ createContentRecorder(displayInfo);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+
+ float xScale = 4f;
+ float yScale = 2f;
+ verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, xScale, 0, 0,
+ yScale);
+ verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface,
+ inputDisplayInfo.logicalWidth, 0);
+ }
+
+ @Test
+ public void testUpdateMirroredSurface_anisotropicPixel_shrinkCanvas() {
+ mHandleAnisotropicDisplayMirroring = true;
+ int width = mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width() / 2;
+ int height = mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height() / 2;
+ DisplayInfo displayInfo = createDisplayInfo(width, height);
+ DisplayInfo inputDisplayInfo =
+ mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY).getDisplayInfo();
+ displayInfo.physicalXDpi = 2f * inputDisplayInfo.physicalXDpi;
+ displayInfo.physicalYDpi = inputDisplayInfo.physicalYDpi;
+ createContentRecorder(displayInfo);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
+
+ float xScale = 0.5f;
+ float yScale = 0.25f;
+ verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, xScale, 0, 0,
+ yScale);
+ verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, 0,
+ (mSurfaceSize.y - height / 2) / 2);
+ }
+
+ @Test
public void testDisplayContentUpdatesRecording_withoutSurface() {
+ defaultInit();
// GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
// mirror.
setUpDefaultTaskDisplayAreaWindowToken();
@@ -585,6 +754,7 @@
@Test
public void testDisplayContentUpdatesRecording_withSurface() {
+ defaultInit();
// GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
// mirror.
setUpDefaultTaskDisplayAreaWindowToken();
@@ -602,12 +772,13 @@
@Test
public void testDisplayContentUpdatesRecording_displayMirroring() {
+ defaultInit();
// GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
// mirror.
setUpDefaultTaskDisplayAreaWindowToken();
// GIVEN SurfaceControl can successfully mirror the provided surface.
- surfaceControlMirrors(sSurfaceSize);
+ surfaceControlMirrors(mSurfaceSize);
// Initially disable getDisplayIdToMirror since the DMS may create the DC outside the direct
// call in the test. We need to spy on the DC before updateRecording is called or we can't
// verify setDisplayMirroring is called
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java
index 4864868..3cb4a1d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java
@@ -19,6 +19,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import android.os.Handler;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.DexmakerShareClassLoaderRule;
import org.junit.Rule;
@@ -27,11 +28,16 @@
/** The base class which provides the common rule for test classes under wm package. */
class SystemServiceTestsBase {
- @Rule
+ @Rule(order = 0)
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
- @Rule
- public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule();
+
+ @Rule(order = 1)
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Rule(order = 2)
+ public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule(
+ this::onBeforeSystemServicesCreated);
@WindowTestRunner.MethodWrapperRule
public final WindowManagerGlobalLockRule mLockRule =
@@ -65,6 +71,11 @@
}
/**
+ * Called before system services are created
+ */
+ protected void onBeforeSystemServicesCreated() {}
+
+ /**
* Make the system booted, so that {@link ActivityStack#resumeTopActivityInnerLocked} can really
* be executed to update activity state and configuration when resuming the current top.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 7634d9f..2597465 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -134,11 +134,20 @@
private WindowState.PowerManagerWrapper mPowerManagerWrapper;
private InputManagerService mImService;
private InputChannel mInputChannel;
+ private Runnable mOnBeforeServicesCreated;
/**
* Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
*/
SurfaceControl.Transaction mTransaction;
+ public SystemServicesTestRule(Runnable onBeforeServicesCreated) {
+ mOnBeforeServicesCreated = onBeforeServicesCreated;
+ }
+
+ public SystemServicesTestRule() {
+ this(/* onBeforeServicesCreated= */ null);
+ }
+
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@@ -168,6 +177,10 @@
}
private void setUp() {
+ if (mOnBeforeServicesCreated != null) {
+ mOnBeforeServicesCreated.run();
+ }
+
// Use stubOnly() to reduce memory usage if it doesn't need verification.
final MockSettings spyStubOnly = withSettings().stubOnly()
.defaultAnswer(CALLS_REAL_METHODS);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7a0bf90..540cecf 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1056,6 +1056,14 @@
"carrier_use_ims_first_for_emergency_bool";
/**
+ * When {@code true}, this carrier will preferentially dial normal routed emergency calls over
+ * an in-service SIM if one is available.
+ * @hide
+ */
+ public static final String KEY_PREFER_IN_SERVICE_SIM_FOR_NORMAL_ROUTED_EMERGENCY_CALLS_BOOL =
+ "prefer_in_service_sim_for_normal_routed_emergency_calls_bool";
+
+ /**
* When {@code true}, the determination of whether to place a call as an emergency call will be
* based on the known {@link android.telephony.emergency.EmergencyNumber}s for the SIM on which
* the call is being placed. In a dual SIM scenario, if Sim A has the emergency numbers
@@ -9874,6 +9882,8 @@
sDefaults.putBoolean(KEY_CARRIER_IMS_GBA_REQUIRED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL, true);
+ sDefaults.putBoolean(KEY_PREFER_IN_SERVICE_SIM_FOR_NORMAL_ROUTED_EMERGENCY_CALLS_BOOL,
+ false);
sDefaults.putBoolean(KEY_USE_ONLY_DIALED_SIM_ECC_LIST_BOOL, false);
sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, "");
sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, "");
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index e9af486..11cbcb1 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -15,6 +15,7 @@
*/
package android.telephony.data;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -35,6 +36,7 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.telephony.flags.Flags;
import com.android.telephony.Rlog;
import java.lang.annotation.Retention;
@@ -121,6 +123,9 @@
public static final int TYPE_BIP = ApnTypes.BIP;
/** APN type for ENTERPRISE. */
public static final int TYPE_ENTERPRISE = ApnTypes.ENTERPRISE;
+ /** APN type for RCS (Rich Communication Services). */
+ @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+ public static final int TYPE_RCS = ApnTypes.RCS;
/** @hide */
@IntDef(flag = true, prefix = {"TYPE_"}, value = {
@@ -139,6 +144,7 @@
TYPE_BIP,
TYPE_VSIM,
TYPE_ENTERPRISE,
+ TYPE_RCS
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApnType {
@@ -356,6 +362,17 @@
@SystemApi
public static final String TYPE_ENTERPRISE_STRING = "enterprise";
+ /**
+ * APN type for RCS (Rich Communication Services)
+ *
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+ @SystemApi
+ public static final String TYPE_RCS_STRING = "rcs";
+
/** @hide */
@IntDef(prefix = { "AUTH_TYPE_" }, value = {
@@ -424,6 +441,26 @@
@Retention(RetentionPolicy.SOURCE)
public @interface MvnoType {}
+ /**
+ * Indicating this APN can be used when the device is using terrestrial cellular networks.
+ * @hide
+ */
+ public static final int INFRASTRUCTURE_CELLULAR = 1 << 0;
+
+ /**
+ * Indicating this APN can be used when the device is attached to satellites.
+ * @hide
+ */
+ public static final int INFRASTRUCTURE_SATELLITE = 1 << 1;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "INFRASTRUCTURE_" }, value = {
+ INFRASTRUCTURE_CELLULAR,
+ INFRASTRUCTURE_SATELLITE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InfrastructureBitmask {}
+
private static final Map<String, Integer> APN_TYPE_STRING_MAP;
private static final Map<Integer, String> APN_TYPE_INT_MAP;
private static final Map<String, Integer> PROTOCOL_STRING_MAP;
@@ -449,6 +486,7 @@
APN_TYPE_STRING_MAP.put(TYPE_ENTERPRISE_STRING, TYPE_ENTERPRISE);
APN_TYPE_STRING_MAP.put(TYPE_VSIM_STRING, TYPE_VSIM);
APN_TYPE_STRING_MAP.put(TYPE_BIP_STRING, TYPE_BIP);
+ APN_TYPE_STRING_MAP.put(TYPE_RCS_STRING, TYPE_RCS);
APN_TYPE_INT_MAP = new ArrayMap<>();
APN_TYPE_INT_MAP.put(TYPE_DEFAULT, TYPE_DEFAULT_STRING);
@@ -466,6 +504,7 @@
APN_TYPE_INT_MAP.put(TYPE_ENTERPRISE, TYPE_ENTERPRISE_STRING);
APN_TYPE_INT_MAP.put(TYPE_VSIM, TYPE_VSIM_STRING);
APN_TYPE_INT_MAP.put(TYPE_BIP, TYPE_BIP_STRING);
+ APN_TYPE_INT_MAP.put(TYPE_RCS, TYPE_RCS_STRING);
PROTOCOL_STRING_MAP = new ArrayMap<>();
PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP);
@@ -528,6 +567,7 @@
private final int mCarrierId;
private final int mSkip464Xlat;
private final boolean mAlwaysOn;
+ private final @InfrastructureBitmask int mInfrastructureBitmask;
/**
* Returns the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought
@@ -916,6 +956,29 @@
return mAlwaysOn;
}
+ /**
+ * Check if this APN can be used when the device is using certain infrastructure(s).
+ *
+ * @param infrastructures The infrastructure(s) the device is using.
+ *
+ * @return {@code true} if this APN can be used.
+ * @hide
+ */
+ public boolean isForInfrastructure(@InfrastructureBitmask int infrastructures) {
+ return (mInfrastructureBitmask & infrastructures) != 0;
+ }
+
+ /**
+ * @return The infrastructure bitmask of which the APN can be used on. For example, some APNs
+ * can only be used when the device is on cellular, on satellite, or both.
+ *
+ * @hide
+ */
+ @InfrastructureBitmask
+ public int getInfrastructureBitmask() {
+ return mInfrastructureBitmask;
+ }
+
private ApnSetting(Builder builder) {
this.mEntryName = builder.mEntryName;
this.mApnName = builder.mApnName;
@@ -952,6 +1015,7 @@
this.mCarrierId = builder.mCarrierId;
this.mSkip464Xlat = builder.mSkip464Xlat;
this.mAlwaysOn = builder.mAlwaysOn;
+ this.mInfrastructureBitmask = builder.mInfrastructureBitmask;
}
/**
@@ -1031,6 +1095,8 @@
cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID)))
.setSkip464Xlat(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT)))
.setAlwaysOn(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.ALWAYS_ON)) == 1)
+ .setInfrastructureBitmask(cursor.getInt(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.INFRASTRUCTURE_BITMASK)))
.buildWithoutCheck();
}
@@ -1070,6 +1136,7 @@
.setCarrierId(apn.mCarrierId)
.setSkip464Xlat(apn.mSkip464Xlat)
.setAlwaysOn(apn.mAlwaysOn)
+ .setInfrastructureBitmask(apn.mInfrastructureBitmask)
.buildWithoutCheck();
}
@@ -1115,6 +1182,7 @@
sb.append(", ").append(mCarrierId);
sb.append(", ").append(mSkip464Xlat);
sb.append(", ").append(mAlwaysOn);
+ sb.append(", ").append(mInfrastructureBitmask);
sb.append(", ").append(Objects.hash(mUser, mPassword));
return sb.toString();
}
@@ -1179,7 +1247,7 @@
mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask,
mLingeringNetworkTypeBitmask, mProfileId, mPersistent, mMaxConns, mWaitTime,
mMaxConnsTime, mMvnoType, mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat,
- mAlwaysOn);
+ mAlwaysOn, mInfrastructureBitmask);
}
@Override
@@ -1191,36 +1259,37 @@
ApnSetting other = (ApnSetting) o;
return mEntryName.equals(other.mEntryName)
- && Objects.equals(mId, other.mId)
+ && mId == other.mId
&& Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
&& Objects.equals(mApnName, other.mApnName)
&& Objects.equals(mProxyAddress, other.mProxyAddress)
&& Objects.equals(mMmsc, other.mMmsc)
&& Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
- && Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
- && Objects.equals(mProxyPort, other.mProxyPort)
+ && mMmsProxyPort == other.mMmsProxyPort
+ && mProxyPort == other.mProxyPort
&& Objects.equals(mUser, other.mUser)
&& Objects.equals(mPassword, other.mPassword)
- && Objects.equals(mAuthType, other.mAuthType)
- && Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
- && Objects.equals(mProtocol, other.mProtocol)
- && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
- && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
- && Objects.equals(mProfileId, other.mProfileId)
- && Objects.equals(mPersistent, other.mPersistent)
- && Objects.equals(mMaxConns, other.mMaxConns)
- && Objects.equals(mWaitTime, other.mWaitTime)
- && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
- && Objects.equals(mMtuV4, other.mMtuV4)
- && Objects.equals(mMtuV6, other.mMtuV6)
- && Objects.equals(mMvnoType, other.mMvnoType)
+ && mAuthType == other.mAuthType
+ && mApnTypeBitmask == other.mApnTypeBitmask
+ && mProtocol == other.mProtocol
+ && mRoamingProtocol == other.mRoamingProtocol
+ && mCarrierEnabled == other.mCarrierEnabled
+ && mProfileId == other.mProfileId
+ && mPersistent == other.mPersistent
+ && mMaxConns == other.mMaxConns
+ && mWaitTime == other.mWaitTime
+ && mMaxConnsTime == other.mMaxConnsTime
+ && mMtuV4 == other.mMtuV4
+ && mMtuV6 == other.mMtuV6
+ && mMvnoType == other.mMvnoType
&& Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
- && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
- && Objects.equals(mLingeringNetworkTypeBitmask, other.mLingeringNetworkTypeBitmask)
- && Objects.equals(mApnSetId, other.mApnSetId)
- && Objects.equals(mCarrierId, other.mCarrierId)
- && Objects.equals(mSkip464Xlat, other.mSkip464Xlat)
- && Objects.equals(mAlwaysOn, other.mAlwaysOn);
+ && mNetworkTypeBitmask == other.mNetworkTypeBitmask
+ && mLingeringNetworkTypeBitmask == other.mLingeringNetworkTypeBitmask
+ && mApnSetId == other.mApnSetId
+ && mCarrierId == other.mCarrierId
+ && mSkip464Xlat == other.mSkip464Xlat
+ && mAlwaysOn == other.mAlwaysOn
+ && mInfrastructureBitmask == other.mInfrastructureBitmask;
}
/**
@@ -1270,7 +1339,8 @@
&& Objects.equals(mApnSetId, other.mApnSetId)
&& Objects.equals(mCarrierId, other.mCarrierId)
&& Objects.equals(mSkip464Xlat, other.mSkip464Xlat)
- && Objects.equals(mAlwaysOn, other.mAlwaysOn);
+ && Objects.equals(mAlwaysOn, other.mAlwaysOn)
+ && Objects.equals(mInfrastructureBitmask, other.mInfrastructureBitmask);
}
/**
@@ -1307,7 +1377,8 @@
&& Objects.equals(this.mApnSetId, other.mApnSetId)
&& Objects.equals(this.mCarrierId, other.mCarrierId)
&& Objects.equals(this.mSkip464Xlat, other.mSkip464Xlat)
- && Objects.equals(this.mAlwaysOn, other.mAlwaysOn);
+ && Objects.equals(this.mAlwaysOn, other.mAlwaysOn)
+ && Objects.equals(this.mInfrastructureBitmask, other.mInfrastructureBitmask);
}
// Equal or one is null.
@@ -1379,6 +1450,7 @@
apnValue.put(Telephony.Carriers.CARRIER_ID, mCarrierId);
apnValue.put(Telephony.Carriers.SKIP_464XLAT, mSkip464Xlat);
apnValue.put(Telephony.Carriers.ALWAYS_ON, mAlwaysOn);
+ apnValue.put(Telephony.Carriers.INFRASTRUCTURE_BITMASK, mInfrastructureBitmask);
return apnValue;
}
@@ -1651,6 +1723,7 @@
dest.writeInt(mCarrierId);
dest.writeInt(mSkip464Xlat);
dest.writeBoolean(mAlwaysOn);
+ dest.writeInt(mInfrastructureBitmask);
}
private static ApnSetting readFromParcel(Parcel in) {
@@ -1686,6 +1759,7 @@
.setCarrierId(in.readInt())
.setSkip464Xlat(in.readInt())
.setAlwaysOn(in.readBoolean())
+ .setInfrastructureBitmask(in.readInt())
.buildWithoutCheck();
}
@@ -1767,6 +1841,7 @@
private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
private int mSkip464Xlat = Carriers.SKIP_464XLAT_DEFAULT;
private boolean mAlwaysOn;
+ private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR;
/**
* Default constructor for Builder.
@@ -2189,6 +2264,22 @@
}
/**
+ * Set the infrastructure bitmask.
+ *
+ * @param infrastructureBitmask The infrastructure bitmask of which the APN can be used on.
+ * For example, some APNs can only be used when the device is on cellular, on satellite, or
+ * both.
+ *
+ * @return The builder.
+ * @hide
+ */
+ @NonNull
+ public Builder setInfrastructureBitmask(@InfrastructureBitmask int infrastructureBitmask) {
+ this.mInfrastructureBitmask = infrastructureBitmask;
+ return this;
+ }
+
+ /**
* Builds {@link ApnSetting} from this builder.
*
* @return {@code null} if {@link #setApnName(String)} or {@link #setEntryName(String)}
@@ -2198,7 +2289,7 @@
public ApnSetting build() {
if ((mApnTypeBitmask & (TYPE_DEFAULT | TYPE_MMS | TYPE_SUPL | TYPE_DUN | TYPE_HIPRI
| TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX
- | TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE)) == 0
+ | TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE | TYPE_RCS)) == 0
|| TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) {
return null;
}
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index f346b92..88a32d1 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -431,6 +431,8 @@
return ApnSetting.TYPE_VSIM;
case NetworkCapabilities.NET_CAPABILITY_ENTERPRISE:
return ApnSetting.TYPE_ENTERPRISE;
+ case NetworkCapabilities.NET_CAPABILITY_RCS:
+ return ApnSetting.TYPE_RCS;
default:
return ApnSetting.TYPE_NONE;
}
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 82aa85d..f4f2be6 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -53,7 +53,17 @@
}
filegroup {
- name: "FlickerTestsAppLaunch-src",
+ name: "FlickerTestsAppLaunchCommon-src",
+ srcs: ["src/**/launch/common/*.kt"],
+}
+
+filegroup {
+ name: "FlickerTestsAppLaunch1-src",
+ srcs: ["src/**/launch/OpenApp*.kt"],
+}
+
+filegroup {
+ name: "FlickerTestsAppLaunch2-src",
srcs: ["src/**/launch/*.kt"],
}
@@ -119,7 +129,8 @@
exclude_srcs: [
":FlickerTestsAppClose-src",
":FlickerTestsIme-src",
- ":FlickerTestsAppLaunch-src",
+ ":FlickerTestsAppLaunch1-src",
+ ":FlickerTestsAppLaunch2-src",
":FlickerTestsQuickswitch-src",
":FlickerTestsRotation-src",
":FlickerTestsNotification-src",
@@ -162,7 +173,8 @@
instrumentation_target_package: "com.android.server.wm.flicker.launch",
srcs: [
":FlickerTestsBase-src",
- ":FlickerTestsAppLaunch-src",
+ ":FlickerTestsAppLaunchCommon-src",
+ ":FlickerTestsAppLaunch2-src",
],
exclude_srcs: [
":FlickerTestsActivityEmbedding-src",
@@ -170,6 +182,39 @@
}
android_test {
+ name: "FlickerTestsAppLaunch1",
+ defaults: ["FlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestAppLaunch.xml"],
+ package_name: "com.android.server.wm.flicker.launch",
+ instrumentation_target_package: "com.android.server.wm.flicker.launch",
+ srcs: [
+ ":FlickerTestsBase-src",
+ ":FlickerTestsAppLaunchCommon-src",
+ ":FlickerTestsAppLaunch1-src",
+ ],
+ exclude_srcs: [
+ ":FlickerTestsActivityEmbedding-src",
+ ],
+}
+
+android_test {
+ name: "FlickerTestsAppLaunch2",
+ defaults: ["FlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestAppLaunch.xml"],
+ package_name: "com.android.server.wm.flicker.launch",
+ instrumentation_target_package: "com.android.server.wm.flicker.launch",
+ srcs: [
+ ":FlickerTestsBase-src",
+ ":FlickerTestsAppLaunchCommon-src",
+ ":FlickerTestsAppLaunch2-src",
+ ],
+ exclude_srcs: [
+ ":FlickerTestsActivityEmbedding-src",
+ ":FlickerTestsAppLaunch1-src",
+ ],
+}
+
+android_test {
name: "FlickerTestsNotification",
defaults: ["FlickerTestsDefault"],
additional_manifests: ["manifests/AndroidManifestNotification.xml"],
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index 48d5041..f788efa 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -16,13 +16,11 @@
package com.android.server.wm.flicker.launch
-import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
import androidx.test.filters.FlakyTest
+import com.android.server.wm.flicker.launch.common.OpenAppFromIconTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -54,28 +52,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class OpenAppFromIconColdTest(flicker: LegacyFlickerTest) :
- OpenAppFromLauncherTransition(flicker) {
- /** {@inheritDoc} */
- override val transition: FlickerBuilder.() -> Unit
- get() = {
- super.transition(this)
- setup {
- if (flicker.scenario.isTablet) {
- tapl.setExpectedRotation(flicker.scenario.startRotation.value)
- } else {
- tapl.setExpectedRotation(Rotation.ROTATION_0.value)
- }
- RemoveAllTasksButHomeRule.removeAllTasksButHome()
- }
- transitions {
- tapl
- .goHome()
- .switchToAllApps()
- .getAppIcon(testApp.appName)
- .launch(testApp.packageName)
- }
- teardown { testApp.exit(wmHelper) }
- }
+ OpenAppFromIconTransition(flicker) {
@FlakyTest(bugId = 240916028)
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
index f575fcc..d86dc50 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
@@ -21,6 +21,7 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
index 93d0520..be07053 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
@@ -25,6 +25,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
index 78b58f4..f66eff9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
@@ -24,6 +24,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index 3f931c4..65214764 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -27,6 +27,7 @@
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.launch.common.OpenAppFromLockscreenTransition
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Ignore
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index b85362a..4d31c28 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -25,6 +25,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
index 1bdb6e71..42e34b3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
@@ -30,6 +30,7 @@
import android.view.KeyEvent
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
import org.junit.FixMethodOrder
import org.junit.Ignore
import org.junit.Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
deleted file mode 100644
index 3d9c067..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.launch
-
-import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.helpers.TransferSplashscreenAppHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test cold launching an app from launcher
- *
- * To run this test: `atest FlickerTests:OpenTransferSplashscreenAppFromLauncherTransition`
- *
- * Actions:
- * ```
- * Inherit from OpenAppFromIconColdTest, Launch an app [testApp] with an animated splash screen
- * by clicking it's icon on all apps, and wait for transfer splash screen complete
- * ```
- *
- * Notes:
- * ```
- * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
- * are inherited [OpenAppTransition]
- * 2. Verify no flickering when transfer splash screen to app window.
- * ```
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenTransferSplashscreenAppFromLauncherTransition(flicker: LegacyFlickerTest) :
- OpenAppFromIconColdTest(flicker) {
- override val testApp = TransferSplashscreenAppHelper(instrumentation)
-
- /**
- * Checks that [ComponentNameMatcher.LAUNCHER] window is the top window at the start of the
- * transition, and is replaced by [ComponentNameMatcher.SPLASH_SCREEN], then [testApp] remains
- * visible until the end
- */
- @Presubmit
- @Test
- fun appWindowAfterSplash() {
- flicker.assertWm {
- this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
- .then()
- .isAppWindowOnTop(ComponentNameMatcher.SPLASH_SCREEN)
- .then()
- .isAppWindowOnTop(testApp)
- .isAppWindowInvisible(ComponentNameMatcher.SPLASH_SCREEN)
- }
- }
-
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
new file mode 100644
index 0000000..c854701
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch.common
+
+import android.tools.common.Rotation
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+
+abstract class OpenAppFromIconTransition(flicker: LegacyFlickerTest) :
+ OpenAppFromLauncherTransition(flicker) {
+ /** {@inheritDoc} */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ super.transition(this)
+ setup {
+ if (flicker.scenario.isTablet) {
+ tapl.setExpectedRotation(flicker.scenario.startRotation.value)
+ } else {
+ tapl.setExpectedRotation(Rotation.ROTATION_0.value)
+ }
+ RemoveAllTasksButHomeRule.removeAllTasksButHome()
+ }
+ transitions {
+ tapl
+ .goHome()
+ .switchToAllApps()
+ .getAppIcon(testApp.appName)
+ .launch(testApp.packageName)
+ }
+ teardown { testApp.exit(wmHelper) }
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
similarity index 95%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
index 4fc9bcb..9d7096e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.launch
+package com.android.server.wm.flicker.launch.common
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
similarity index 97%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
index cc501e6..7b08843 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.launch
+package com.android.server.wm.flicker.launch.common
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
similarity index 98%
rename from tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
rename to tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
index bb11be5..989619e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.launch
+package com.android.server.wm.flicker.launch.common
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt
new file mode 100644
index 0000000..2e9620b
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/common/OpenTransferSplashscreenAppFromLauncherTransition.kt
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch.common
+
+import android.platform.test.annotations.Presubmit
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.helpers.TransferSplashscreenAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test cold launching an app from launcher
+ *
+ * To run this test: `atest FlickerTests:OpenTransferSplashscreenAppFromLauncherTransition`
+ *
+ * Actions:
+ * ```
+ * Inherit from OpenAppFromIconColdTest, Launch an app [testApp] with an animated splash screen
+ * by clicking it's icon on all apps, and wait for transfer splash screen complete
+ * ```
+ *
+ * Notes:
+ * ```
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Verify no flickering when transfer splash screen to app window.
+ * ```
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenTransferSplashscreenAppFromLauncherTransition(flicker: LegacyFlickerTest) :
+ OpenAppFromIconTransition(flicker) {
+ override val testApp = TransferSplashscreenAppHelper(instrumentation)
+
+ /**
+ * Checks that [ComponentNameMatcher.LAUNCHER] window is the top window at the start of the
+ * transition, and is replaced by [ComponentNameMatcher.SPLASH_SCREEN], then [testApp] remains
+ * visible until the end
+ */
+ @Presubmit
+ @Test
+ fun appWindowAfterSplash() {
+ flicker.assertWm {
+ this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
+ .then()
+ .isAppWindowOnTop(ComponentNameMatcher.SPLASH_SCREEN)
+ .then()
+ .isAppWindowOnTop(testApp)
+ .isAppWindowInvisible(ComponentNameMatcher.SPLASH_SCREEN)
+ }
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun focusChanges() {
+ super.focusChanges()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun appWindowReplacesLauncherAsTopWindow() {
+ super.appWindowReplacesLauncherAsTopWindow()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun appWindowAsTopWindowAtEnd() {
+ super.appWindowAsTopWindowAtEnd()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun appWindowBecomesTopWindow() {
+ super.appWindowBecomesTopWindow()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun appWindowBecomesVisible() {
+ super.appWindowBecomesVisible()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun appWindowIsTopWindowAtEnd() {
+ super.appWindowIsTopWindowAtEnd()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun appLayerBecomesVisible() {
+ super.appLayerBecomesVisible()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun appLayerReplacesLauncher() {
+ super.appLayerReplacesLauncher()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun cujCompleted() {
+ super.cujCompleted()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun entireScreenCovered() {
+ super.entireScreenCovered()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun navBarLayerIsVisibleAtStartAndEnd() {
+ super.navBarLayerIsVisibleAtStartAndEnd()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun navBarLayerPositionAtStartAndEnd() {
+ super.navBarLayerPositionAtStartAndEnd()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun navBarWindowIsAlwaysVisible() {
+ super.navBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun navBarWindowIsVisibleAtStartAndEnd() {
+ super.navBarWindowIsVisibleAtStartAndEnd()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun statusBarLayerIsVisibleAtStartAndEnd() {
+ super.statusBarLayerIsVisibleAtStartAndEnd()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun statusBarLayerPositionAtStartAndEnd() {
+ super.statusBarLayerPositionAtStartAndEnd()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun statusBarWindowIsAlwaysVisible() {
+ super.statusBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun taskBarLayerIsVisibleAtStartAndEnd() {
+ super.taskBarLayerIsVisibleAtStartAndEnd()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun taskBarWindowIsAlwaysVisible() {
+ super.taskBarWindowIsAlwaysVisible()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ @FlakyTest(bugId = 240916028)
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
+ }
+}