Merge "Population Density Provider: add cache hint" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 3c2ae5a..371177c 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -1220,6 +1220,17 @@
}
java_aconfig_library {
+ name: "device_policy_aconfig_flags_java_export",
+ aconfig_declarations: "device_policy_aconfig_flags",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+ min_sdk_version: "30",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
+}
+
+java_aconfig_library {
name: "device_policy_aconfig_flags_lib_host",
aconfig_declarations: "device_policy_aconfig_flags",
host_supported: true,
diff --git a/core/api/current.txt b/core/api/current.txt
index 1b42977..2fa22d5 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -17082,7 +17082,7 @@
method public void arcTo(@NonNull android.graphics.RectF, float, float);
method public void arcTo(float, float, float, float, float, float, boolean);
method public void close();
- method @Deprecated public void computeBounds(@NonNull android.graphics.RectF, boolean);
+ method public void computeBounds(@NonNull android.graphics.RectF, boolean);
method @FlaggedApi("com.android.graphics.flags.exact_compute_bounds") public void computeBounds(@NonNull android.graphics.RectF);
method public void conicTo(float, float, float, float, float);
method public void cubicTo(float, float, float, float, float, float);
@@ -40810,13 +40810,14 @@
public abstract class AutofillService extends android.app.Service {
ctor public AutofillService();
- method @Nullable public final android.service.autofill.FillEventHistory getFillEventHistory();
+ method @Deprecated @FlaggedApi("android.service.autofill.autofill_session_destroyed") @Nullable public final android.service.autofill.FillEventHistory getFillEventHistory();
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConnected();
method public void onDisconnected();
method public abstract void onFillRequest(@NonNull android.service.autofill.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback);
method public abstract void onSaveRequest(@NonNull android.service.autofill.SaveRequest, @NonNull android.service.autofill.SaveCallback);
method public void onSavedDatasetsInfoRequest(@NonNull android.service.autofill.SavedDatasetsInfoCallback);
+ method @FlaggedApi("android.service.autofill.autofill_session_destroyed") public void onSessionDestroyed(@Nullable android.service.autofill.FillEventHistory);
field public static final String EXTRA_FILL_RESPONSE = "android.service.autofill.extra.FILL_RESPONSE";
field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
field public static final String SERVICE_META_DATA = "android.autofill";
diff --git a/core/java/android/app/AppOpsManager.aidl b/core/java/android/app/AppOpsManager.aidl
index b4dee2e..56ed290 100644
--- a/core/java/android/app/AppOpsManager.aidl
+++ b/core/java/android/app/AppOpsManager.aidl
@@ -19,6 +19,7 @@
parcelable AppOpsManager.PackageOps;
parcelable AppOpsManager.NoteOpEventProxyInfo;
parcelable AppOpsManager.NoteOpEvent;
+parcelable AppOpsManager.NotedOp;
parcelable AppOpsManager.OpFeatureEntry;
parcelable AppOpsManager.OpEntry;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 1913812..c789e28 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -262,6 +262,24 @@
private static final Object sLock = new Object();
+ // A map that records noted times for each op.
+ private final ArrayMap<NotedOp, Integer> mPendingNotedOps = new ArrayMap<>();
+ private final HandlerThread mHandlerThread;
+ private final Handler mHandler;
+ private static final int NOTE_OP_BATCHING_DELAY_MILLIS = 1000;
+
+ private boolean isNoteOpBatchingSupported() {
+ // If noteOp is called from system server no IPC is made, hence we don't need batching.
+ if (Process.myUid() == Process.SYSTEM_UID) {
+ return false;
+ }
+ return Flags.noteOpBatchingEnabled();
+ }
+
+ private final Object mBatchedNoteOpLock = new Object();
+ @GuardedBy("mBatchedNoteOpLock")
+ private boolean mIsBatchedNoteOpCallScheduled = false;
+
/** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */
@GuardedBy("sLock")
private static @Nullable OnOpNotedCallback sOnOpNotedCallback;
@@ -7466,6 +7484,135 @@
}
/**
+ * A NotedOp is an app op grouped in noteOp API and sent to the system server in a batch
+ *
+ * @hide
+ */
+ public static final class NotedOp implements Parcelable {
+ private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp;
+ private final @IntRange(from = 0) int mUid;
+ private final @Nullable String mPackageName;
+ private final @Nullable String mAttributionTag;
+ private final int mVirtualDeviceId;
+ private final @Nullable String mMessage;
+ private final boolean mShouldCollectAsyncNotedOp;
+ private final boolean mShouldCollectMessage;
+
+ public NotedOp(int op, int uid, @Nullable String packageName,
+ @Nullable String attributionTag, int virtualDeviceId, @Nullable String message,
+ boolean shouldCollectAsyncNotedOp, boolean shouldCollectMessage) {
+ mOp = op;
+ mUid = uid;
+ mPackageName = packageName;
+ mAttributionTag = attributionTag;
+ mVirtualDeviceId = virtualDeviceId;
+ mMessage = message;
+ mShouldCollectAsyncNotedOp = shouldCollectAsyncNotedOp;
+ mShouldCollectMessage = shouldCollectMessage;
+ }
+
+ NotedOp(Parcel source) {
+ mOp = source.readInt();
+ mUid = source.readInt();
+ mPackageName = source.readString();
+ mAttributionTag = source.readString();
+ mVirtualDeviceId = source.readInt();
+ mMessage = source.readString();
+ mShouldCollectAsyncNotedOp = source.readBoolean();
+ mShouldCollectMessage = source.readBoolean();
+ }
+
+ public int getOp() {
+ return mOp;
+ }
+
+ public int getUid() {
+ return mUid;
+ }
+
+ public @Nullable String getPackageName() {
+ return mPackageName;
+ }
+
+ public @Nullable String getAttributionTag() {
+ return mAttributionTag;
+ }
+
+ public int getVirtualDeviceId() {
+ return mVirtualDeviceId;
+ }
+
+ public @Nullable String getMessage() {
+ return mMessage;
+ }
+
+ public boolean getShouldCollectAsyncNotedOp() {
+ return mShouldCollectAsyncNotedOp;
+ }
+
+ public boolean getShouldCollectMessage() {
+ return mShouldCollectMessage;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mOp);
+ dest.writeInt(mUid);
+ dest.writeString(mPackageName);
+ dest.writeString(mAttributionTag);
+ dest.writeInt(mVirtualDeviceId);
+ dest.writeString(mMessage);
+ dest.writeBoolean(mShouldCollectAsyncNotedOp);
+ dest.writeBoolean(mShouldCollectMessage);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ NotedOp that = (NotedOp) o;
+ return mOp == that.mOp && mUid == that.mUid && Objects.equals(mPackageName,
+ that.mPackageName) && Objects.equals(mAttributionTag, that.mAttributionTag)
+ && mVirtualDeviceId == that.mVirtualDeviceId && Objects.equals(mMessage,
+ that.mMessage) && Objects.equals(mShouldCollectAsyncNotedOp,
+ that.mShouldCollectAsyncNotedOp) && Objects.equals(mShouldCollectMessage,
+ that.mShouldCollectMessage);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mOp, mUid, mPackageName, mAttributionTag, mVirtualDeviceId,
+ mMessage, mShouldCollectAsyncNotedOp, mShouldCollectMessage);
+ }
+
+ @Override
+ public String toString() {
+ return "NotedOp{" + "mOp=" + mOp + ", mUid=" + mUid + ", mPackageName=" + mPackageName
+ + ", mAttributionTag=" + mAttributionTag + ", mVirtualDeviceId="
+ + mVirtualDeviceId + ", mMessage=" + mMessage + ", mShouldCollectAsyncNotedOp="
+ + mShouldCollectAsyncNotedOp + ", mShouldCollectMessage="
+ + mShouldCollectMessage + "}";
+ }
+
+
+ public static final @NonNull Creator<NotedOp> CREATOR =
+ new Creator<>() {
+ @Override public NotedOp createFromParcel(Parcel source) {
+ return new NotedOp(source);
+ }
+
+ @Override public NotedOp[] newArray(int size) {
+ return new NotedOp[size];
+ }
+ };
+ }
+
+ /**
* Computes the sum of the counts for the given flags in between the begin and
* end UID states.
*
@@ -7979,6 +8126,9 @@
AppOpsManager(Context context, IAppOpsService service) {
mContext = context;
mService = service;
+ mHandlerThread = new HandlerThread("AppOpsManager");
+ mHandlerThread.start();
+ mHandler = mHandlerThread.getThreadHandler();
if (mContext != null) {
final PackageManager pm = mContext.getPackageManager();
@@ -9315,15 +9465,74 @@
}
}
- SyncNotedAppOp syncOp;
- if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) {
- syncOp = mService.noteOperation(op, uid, packageName, attributionTag,
- collectionMode == COLLECT_ASYNC, message, shouldCollectMessage);
- } else {
- syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag,
- virtualDeviceId, collectionMode == COLLECT_ASYNC, message,
- shouldCollectMessage);
+ SyncNotedAppOp syncOp = null;
+ boolean skipBinderCall = false;
+ if (isNoteOpBatchingSupported()) {
+ int mode = sAppOpModeCache.query(
+ new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag,
+ "noteOpNoThrow"));
+ // For FOREGROUND mode, we still need to make a binder call to the system service
+ // to translate it to ALLOWED or IGNORED. So no batching is needed.
+ if (mode != MODE_FOREGROUND) {
+ synchronized (mBatchedNoteOpLock) {
+ NotedOp notedOp = new NotedOp(op, uid, packageName, attributionTag,
+ virtualDeviceId, message, collectionMode == COLLECT_ASYNC,
+ shouldCollectMessage);
+
+ // Batch same noteOp calls and send them with their counters to the system
+ // service asynchronously. The time window for batching is specified in
+ // NOTE_OP_BATCHING_DELAY_MILLIS. Always allow the first noteOp call to go
+ // through binder API. Accumulate subsequent same noteOp calls during the
+ // time window in mPendingNotedOps.
+ if (!mPendingNotedOps.containsKey(notedOp)) {
+ mPendingNotedOps.put(notedOp, 0);
+ } else {
+ skipBinderCall = true;
+ mPendingNotedOps.merge(notedOp, 1, Integer::sum);
+ }
+
+ if (!mIsBatchedNoteOpCallScheduled) {
+ mHandler.postDelayed(() -> {
+ ArrayMap<NotedOp, Integer> pendingNotedOpsCopy;
+ synchronized(mBatchedNoteOpLock) {
+ mIsBatchedNoteOpCallScheduled = false;
+ pendingNotedOpsCopy =
+ new ArrayMap<NotedOp, Integer>(mPendingNotedOps);
+ mPendingNotedOps.clear();
+ }
+ for (int i = pendingNotedOpsCopy.size() - 1; i >= 0; i--) {
+ if (pendingNotedOpsCopy.valueAt(i) == 0) {
+ pendingNotedOpsCopy.removeAt(i);
+ }
+ }
+ if (!pendingNotedOpsCopy.isEmpty()) {
+ try {
+ mService.noteOperationsInBatch(pendingNotedOpsCopy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }, NOTE_OP_BATCHING_DELAY_MILLIS);
+
+ mIsBatchedNoteOpCallScheduled = true;
+ }
+ }
+
+ syncOp = new SyncNotedAppOp(mode, op, attributionTag, packageName);
+ }
}
+
+ if (!skipBinderCall) {
+ if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) {
+ syncOp = mService.noteOperation(op, uid, packageName, attributionTag,
+ collectionMode == COLLECT_ASYNC, message, shouldCollectMessage);
+ } else {
+ syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag,
+ virtualDeviceId, collectionMode == COLLECT_ASYNC, message,
+ shouldCollectMessage);
+ }
+ }
+
if (syncOp.getOpMode() == MODE_ALLOWED) {
if (collectionMode == COLLECT_SELF) {
collectNotedOpForSelf(syncOp);
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index b21defb..8b7ea0f 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -29,7 +29,7 @@
import com.android.internal.util.function.DodecFunction;
import com.android.internal.util.function.HexConsumer;
import com.android.internal.util.function.HexFunction;
-import com.android.internal.util.function.OctFunction;
+import com.android.internal.util.function.NonaFunction;
import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.UndecFunction;
@@ -86,9 +86,9 @@
*/
SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
@Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
- @Nullable String message, boolean shouldCollectMessage,
- @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String,
- Boolean, SyncNotedAppOp> superImpl);
+ @Nullable String message, boolean shouldCollectMessage, int notedCount,
+ @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String,
+ Boolean, Integer, SyncNotedAppOp> superImpl);
/**
* Allows overriding note proxy operation behavior.
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 22bc356..361ba73 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -398,6 +398,7 @@
flag {
name: "split_create_managed_profile_enabled"
+ is_exported: true
namespace: "enterprise"
description: "Split up existing create and provision managed profile API."
bug: "375382324"
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index bf7116d..6855d95 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -50,6 +50,7 @@
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
+import dalvik.annotation.optimization.NeverInline;
import libcore.util.SneakyThrow;
@@ -587,6 +588,17 @@
return parcel;
}
+ @NeverInline
+ private void errorUsedWhileRecycling() {
+ Log.wtf(TAG, "Parcel used while recycled. "
+ + Log.getStackTraceString(new Throwable())
+ + " Original recycle call (if DEBUG_RECYCLE): ", mStack);
+ }
+
+ private void assertNotRecycled() {
+ if (mRecycled) errorUsedWhileRecycling();
+ }
+
/**
* Put a Parcel object back into the pool. You must not touch
* the object after this call.
@@ -635,6 +647,7 @@
* @hide
*/
public void setReadWriteHelper(@Nullable ReadWriteHelper helper) {
+ assertNotRecycled();
mReadWriteHelper = helper != null ? helper : ReadWriteHelper.DEFAULT;
}
@@ -644,6 +657,7 @@
* @hide
*/
public boolean hasReadWriteHelper() {
+ assertNotRecycled();
return (mReadWriteHelper != null) && (mReadWriteHelper != ReadWriteHelper.DEFAULT);
}
@@ -670,6 +684,7 @@
* @hide
*/
public final void markSensitive() {
+ assertNotRecycled();
nativeMarkSensitive(mNativePtr);
}
@@ -686,6 +701,7 @@
* @hide
*/
public final boolean isForRpc() {
+ assertNotRecycled();
return nativeIsForRpc(mNativePtr);
}
@@ -693,21 +709,25 @@
@ParcelFlags
@TestApi
public int getFlags() {
+ assertNotRecycled();
return mFlags;
}
/** @hide */
public void setFlags(@ParcelFlags int flags) {
+ assertNotRecycled();
mFlags = flags;
}
/** @hide */
public void addFlags(@ParcelFlags int flags) {
+ assertNotRecycled();
mFlags |= flags;
}
/** @hide */
private boolean hasFlags(@ParcelFlags int flags) {
+ assertNotRecycled();
return (mFlags & flags) == flags;
}
@@ -720,6 +740,7 @@
// We don't really need to protect it; even if 3p / non-system apps, nothing would happen.
// This would only work when used on a reply parcel by a binder object that's allowed-blocking.
public void setPropagateAllowBlocking() {
+ assertNotRecycled();
addFlags(FLAG_PROPAGATE_ALLOW_BLOCKING);
}
@@ -727,6 +748,7 @@
* Returns the total amount of data contained in the parcel.
*/
public int dataSize() {
+ assertNotRecycled();
return nativeDataSize(mNativePtr);
}
@@ -735,6 +757,7 @@
* parcel. That is, {@link #dataSize}-{@link #dataPosition}.
*/
public final int dataAvail() {
+ assertNotRecycled();
return nativeDataAvail(mNativePtr);
}
@@ -743,6 +766,7 @@
* more than {@link #dataSize}.
*/
public final int dataPosition() {
+ assertNotRecycled();
return nativeDataPosition(mNativePtr);
}
@@ -753,6 +777,7 @@
* data buffer.
*/
public final int dataCapacity() {
+ assertNotRecycled();
return nativeDataCapacity(mNativePtr);
}
@@ -764,6 +789,7 @@
* @param size The new number of bytes in the Parcel.
*/
public final void setDataSize(int size) {
+ assertNotRecycled();
nativeSetDataSize(mNativePtr, size);
}
@@ -773,6 +799,7 @@
* {@link #dataSize}.
*/
public final void setDataPosition(int pos) {
+ assertNotRecycled();
nativeSetDataPosition(mNativePtr, pos);
}
@@ -784,11 +811,13 @@
* with this method.
*/
public final void setDataCapacity(int size) {
+ assertNotRecycled();
nativeSetDataCapacity(mNativePtr, size);
}
/** @hide */
public final boolean pushAllowFds(boolean allowFds) {
+ assertNotRecycled();
return nativePushAllowFds(mNativePtr, allowFds);
}
@@ -809,6 +838,7 @@
* in different versions of the platform.
*/
public final byte[] marshall() {
+ assertNotRecycled();
return nativeMarshall(mNativePtr);
}
@@ -816,15 +846,18 @@
* Fills the raw bytes of this Parcel with the supplied data.
*/
public final void unmarshall(@NonNull byte[] data, int offset, int length) {
+ assertNotRecycled();
nativeUnmarshall(mNativePtr, data, offset, length);
}
public final void appendFrom(Parcel parcel, int offset, int length) {
+ assertNotRecycled();
nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length);
}
/** @hide */
public int compareData(Parcel other) {
+ assertNotRecycled();
return nativeCompareData(mNativePtr, other.mNativePtr);
}
@@ -835,6 +868,7 @@
/** @hide */
public final void setClassCookie(Class clz, Object cookie) {
+ assertNotRecycled();
if (mClassCookies == null) {
mClassCookies = new ArrayMap<>();
}
@@ -844,11 +878,13 @@
/** @hide */
@Nullable
public final Object getClassCookie(Class clz) {
+ assertNotRecycled();
return mClassCookies != null ? mClassCookies.get(clz) : null;
}
/** @hide */
public void removeClassCookie(Class clz, Object expectedCookie) {
+ assertNotRecycled();
if (mClassCookies != null) {
Object removedCookie = mClassCookies.remove(clz);
if (removedCookie != expectedCookie) {
@@ -866,21 +902,25 @@
* @hide
*/
public boolean hasClassCookie(Class clz) {
+ assertNotRecycled();
return mClassCookies != null && mClassCookies.containsKey(clz);
}
/** @hide */
public final void adoptClassCookies(Parcel from) {
+ assertNotRecycled();
mClassCookies = from.mClassCookies;
}
/** @hide */
public Map<Class, Object> copyClassCookies() {
+ assertNotRecycled();
return new ArrayMap<>(mClassCookies);
}
/** @hide */
public void putClassCookies(Map<Class, Object> cookies) {
+ assertNotRecycled();
if (cookies == null) {
return;
}
@@ -894,6 +934,7 @@
* Report whether the parcel contains any marshalled file descriptors.
*/
public boolean hasFileDescriptors() {
+ assertNotRecycled();
return nativeHasFileDescriptors(mNativePtr);
}
@@ -909,6 +950,7 @@
* @throws IllegalArgumentException if the parameters are out of the permitted ranges.
*/
public boolean hasFileDescriptors(int offset, int length) {
+ assertNotRecycled();
return nativeHasFileDescriptorsInRange(mNativePtr, offset, length);
}
@@ -993,6 +1035,7 @@
* @hide
*/
public boolean hasBinders() {
+ assertNotRecycled();
return nativeHasBinders(mNativePtr);
}
@@ -1010,6 +1053,7 @@
* @hide
*/
public boolean hasBinders(int offset, int length) {
+ assertNotRecycled();
return nativeHasBindersInRange(mNativePtr, offset, length);
}
@@ -1020,6 +1064,7 @@
* at the beginning of transactions as a header.
*/
public final void writeInterfaceToken(@NonNull String interfaceName) {
+ assertNotRecycled();
nativeWriteInterfaceToken(mNativePtr, interfaceName);
}
@@ -1030,6 +1075,7 @@
* should propagate to the caller.
*/
public final void enforceInterface(@NonNull String interfaceName) {
+ assertNotRecycled();
nativeEnforceInterface(mNativePtr, interfaceName);
}
@@ -1040,6 +1086,7 @@
* When used over binder, this exception should propagate to the caller.
*/
public void enforceNoDataAvail() {
+ assertNotRecycled();
final int n = dataAvail();
if (n > 0) {
throw new BadParcelableException("Parcel data not fully consumed, unread size: " + n);
@@ -1056,6 +1103,7 @@
* @hide
*/
public boolean replaceCallingWorkSourceUid(int workSourceUid) {
+ assertNotRecycled();
return nativeReplaceCallingWorkSourceUid(mNativePtr, workSourceUid);
}
@@ -1072,6 +1120,7 @@
* @hide
*/
public int readCallingWorkSourceUid() {
+ assertNotRecycled();
return nativeReadCallingWorkSourceUid(mNativePtr);
}
@@ -1081,6 +1130,7 @@
* @param b Bytes to place into the parcel.
*/
public final void writeByteArray(@Nullable byte[] b) {
+ assertNotRecycled();
writeByteArray(b, 0, (b != null) ? b.length : 0);
}
@@ -1092,6 +1142,7 @@
* @param len Number of bytes to write.
*/
public final void writeByteArray(@Nullable byte[] b, int offset, int len) {
+ assertNotRecycled();
if (b == null) {
writeInt(-1);
return;
@@ -1113,6 +1164,7 @@
* @see #readBlob()
*/
public final void writeBlob(@Nullable byte[] b) {
+ assertNotRecycled();
writeBlob(b, 0, (b != null) ? b.length : 0);
}
@@ -1131,6 +1183,7 @@
* @see #readBlob()
*/
public final void writeBlob(@Nullable byte[] b, int offset, int len) {
+ assertNotRecycled();
if (b == null) {
writeInt(-1);
return;
@@ -1149,6 +1202,7 @@
* growing dataCapacity() if needed.
*/
public final void writeInt(int val) {
+ assertNotRecycled();
int err = nativeWriteInt(mNativePtr, val);
if (err != OK) {
nativeSignalExceptionForError(err);
@@ -1160,6 +1214,7 @@
* growing dataCapacity() if needed.
*/
public final void writeLong(long val) {
+ assertNotRecycled();
int err = nativeWriteLong(mNativePtr, val);
if (err != OK) {
nativeSignalExceptionForError(err);
@@ -1171,6 +1226,7 @@
* dataPosition(), growing dataCapacity() if needed.
*/
public final void writeFloat(float val) {
+ assertNotRecycled();
int err = nativeWriteFloat(mNativePtr, val);
if (err != OK) {
nativeSignalExceptionForError(err);
@@ -1182,6 +1238,7 @@
* current dataPosition(), growing dataCapacity() if needed.
*/
public final void writeDouble(double val) {
+ assertNotRecycled();
int err = nativeWriteDouble(mNativePtr, val);
if (err != OK) {
nativeSignalExceptionForError(err);
@@ -1193,16 +1250,19 @@
* growing dataCapacity() if needed.
*/
public final void writeString(@Nullable String val) {
+ assertNotRecycled();
writeString16(val);
}
/** {@hide} */
public final void writeString8(@Nullable String val) {
+ assertNotRecycled();
mReadWriteHelper.writeString8(this, val);
}
/** {@hide} */
public final void writeString16(@Nullable String val) {
+ assertNotRecycled();
mReadWriteHelper.writeString16(this, val);
}
@@ -1214,16 +1274,19 @@
* @hide
*/
public void writeStringNoHelper(@Nullable String val) {
+ assertNotRecycled();
writeString16NoHelper(val);
}
/** {@hide} */
public void writeString8NoHelper(@Nullable String val) {
+ assertNotRecycled();
nativeWriteString8(mNativePtr, val);
}
/** {@hide} */
public void writeString16NoHelper(@Nullable String val) {
+ assertNotRecycled();
nativeWriteString16(mNativePtr, val);
}
@@ -1235,6 +1298,7 @@
* for true or false, respectively, but may change in the future.
*/
public final void writeBoolean(boolean val) {
+ assertNotRecycled();
writeInt(val ? 1 : 0);
}
@@ -1246,6 +1310,7 @@
@UnsupportedAppUsage
@RavenwoodThrow(blockedBy = android.text.Spanned.class)
public final void writeCharSequence(@Nullable CharSequence val) {
+ assertNotRecycled();
TextUtils.writeToParcel(val, this, 0);
}
@@ -1254,6 +1319,7 @@
* growing dataCapacity() if needed.
*/
public final void writeStrongBinder(IBinder val) {
+ assertNotRecycled();
nativeWriteStrongBinder(mNativePtr, val);
}
@@ -1262,6 +1328,7 @@
* growing dataCapacity() if needed.
*/
public final void writeStrongInterface(IInterface val) {
+ assertNotRecycled();
writeStrongBinder(val == null ? null : val.asBinder());
}
@@ -1276,6 +1343,7 @@
* if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.</p>
*/
public final void writeFileDescriptor(@NonNull FileDescriptor val) {
+ assertNotRecycled();
nativeWriteFileDescriptor(mNativePtr, val);
}
@@ -1284,6 +1352,7 @@
* This will be the new name for writeFileDescriptor, for consistency.
**/
public final void writeRawFileDescriptor(@NonNull FileDescriptor val) {
+ assertNotRecycled();
nativeWriteFileDescriptor(mNativePtr, val);
}
@@ -1294,6 +1363,7 @@
* @param value The array of objects to be written.
*/
public final void writeRawFileDescriptorArray(@Nullable FileDescriptor[] value) {
+ assertNotRecycled();
if (value != null) {
int N = value.length;
writeInt(N);
@@ -1313,6 +1383,7 @@
* the future.
*/
public final void writeByte(byte val) {
+ assertNotRecycled();
writeInt(val);
}
@@ -1328,6 +1399,7 @@
* allows you to avoid mysterious type errors at the point of marshalling.
*/
public final void writeMap(@Nullable Map val) {
+ assertNotRecycled();
writeMapInternal((Map<String, Object>) val);
}
@@ -1336,6 +1408,7 @@
* growing dataCapacity() if needed. The Map keys must be String objects.
*/
/* package */ void writeMapInternal(@Nullable Map<String,Object> val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -1361,6 +1434,7 @@
* growing dataCapacity() if needed. The Map keys must be String objects.
*/
/* package */ void writeArrayMapInternal(@Nullable ArrayMap<String, Object> val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -1390,6 +1464,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void writeArrayMap(@Nullable ArrayMap<String, Object> val) {
+ assertNotRecycled();
writeArrayMapInternal(val);
}
@@ -1408,6 +1483,7 @@
*/
public <T extends Parcelable> void writeTypedArrayMap(@Nullable ArrayMap<String, T> val,
int parcelableFlags) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -1429,6 +1505,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void writeArraySet(@Nullable ArraySet<? extends Object> val) {
+ assertNotRecycled();
final int size = (val != null) ? val.size() : -1;
writeInt(size);
for (int i = 0; i < size; i++) {
@@ -1441,6 +1518,7 @@
* growing dataCapacity() if needed.
*/
public final void writeBundle(@Nullable Bundle val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -1454,6 +1532,7 @@
* growing dataCapacity() if needed.
*/
public final void writePersistableBundle(@Nullable PersistableBundle val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -1467,6 +1546,7 @@
* growing dataCapacity() if needed.
*/
public final void writeSize(@NonNull Size val) {
+ assertNotRecycled();
writeInt(val.getWidth());
writeInt(val.getHeight());
}
@@ -1476,6 +1556,7 @@
* growing dataCapacity() if needed.
*/
public final void writeSizeF(@NonNull SizeF val) {
+ assertNotRecycled();
writeFloat(val.getWidth());
writeFloat(val.getHeight());
}
@@ -1486,6 +1567,7 @@
* {@link #writeValue} and must follow the specification there.
*/
public final void writeList(@Nullable List val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -1505,6 +1587,7 @@
* {@link #writeValue} and must follow the specification there.
*/
public final void writeArray(@Nullable Object[] val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -1525,6 +1608,7 @@
* specification there.
*/
public final <T> void writeSparseArray(@Nullable SparseArray<T> val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -1540,6 +1624,7 @@
}
public final void writeSparseBooleanArray(@Nullable SparseBooleanArray val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -1558,6 +1643,7 @@
* @hide
*/
public final void writeSparseIntArray(@Nullable SparseIntArray val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -1573,6 +1659,7 @@
}
public final void writeBooleanArray(@Nullable boolean[] val) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -1607,6 +1694,7 @@
}
private void ensureWithinMemoryLimit(int typeSize, @NonNull int... dimensions) {
+ assertNotRecycled();
// For Multidimensional arrays, Calculate total object
// which will be allocated.
int totalObjects = 1;
@@ -1624,6 +1712,7 @@
}
private void ensureWithinMemoryLimit(int typeSize, int length) {
+ assertNotRecycled();
int estimatedAllocationSize = 0;
try {
estimatedAllocationSize = Math.multiplyExact(typeSize, length);
@@ -1647,6 +1736,7 @@
@Nullable
public final boolean[] createBooleanArray() {
+ assertNotRecycled();
int N = readInt();
ensureWithinMemoryLimit(SIZE_BOOLEAN, N);
// >>2 as a fast divide-by-4 works in the create*Array() functions
@@ -1664,6 +1754,7 @@
}
public final void readBooleanArray(@NonNull boolean[] val) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -1676,6 +1767,7 @@
/** @hide */
public void writeShortArray(@Nullable short[] val) {
+ assertNotRecycled();
if (val != null) {
int n = val.length;
writeInt(n);
@@ -1690,6 +1782,7 @@
/** @hide */
@Nullable
public short[] createShortArray() {
+ assertNotRecycled();
int n = readInt();
ensureWithinMemoryLimit(SIZE_SHORT, n);
if (n >= 0 && n <= (dataAvail() >> 2)) {
@@ -1705,6 +1798,7 @@
/** @hide */
public void readShortArray(@NonNull short[] val) {
+ assertNotRecycled();
int n = readInt();
if (n == val.length) {
for (int i = 0; i < n; i++) {
@@ -1716,6 +1810,7 @@
}
public final void writeCharArray(@Nullable char[] val) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -1729,6 +1824,7 @@
@Nullable
public final char[] createCharArray() {
+ assertNotRecycled();
int N = readInt();
ensureWithinMemoryLimit(SIZE_CHAR, N);
if (N >= 0 && N <= (dataAvail() >> 2)) {
@@ -1743,6 +1839,7 @@
}
public final void readCharArray(@NonNull char[] val) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -1754,6 +1851,7 @@
}
public final void writeIntArray(@Nullable int[] val) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -1767,6 +1865,7 @@
@Nullable
public final int[] createIntArray() {
+ assertNotRecycled();
int N = readInt();
ensureWithinMemoryLimit(SIZE_INT, N);
if (N >= 0 && N <= (dataAvail() >> 2)) {
@@ -1781,6 +1880,7 @@
}
public final void readIntArray(@NonNull int[] val) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -1792,6 +1892,7 @@
}
public final void writeLongArray(@Nullable long[] val) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -1805,6 +1906,7 @@
@Nullable
public final long[] createLongArray() {
+ assertNotRecycled();
int N = readInt();
ensureWithinMemoryLimit(SIZE_LONG, N);
// >>3 because stored longs are 64 bits
@@ -1820,6 +1922,7 @@
}
public final void readLongArray(@NonNull long[] val) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -1831,6 +1934,7 @@
}
public final void writeFloatArray(@Nullable float[] val) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -1844,6 +1948,7 @@
@Nullable
public final float[] createFloatArray() {
+ assertNotRecycled();
int N = readInt();
ensureWithinMemoryLimit(SIZE_FLOAT, N);
// >>2 because stored floats are 4 bytes
@@ -1859,6 +1964,7 @@
}
public final void readFloatArray(@NonNull float[] val) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -1870,6 +1976,7 @@
}
public final void writeDoubleArray(@Nullable double[] val) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -1883,6 +1990,7 @@
@Nullable
public final double[] createDoubleArray() {
+ assertNotRecycled();
int N = readInt();
ensureWithinMemoryLimit(SIZE_DOUBLE, N);
// >>3 because stored doubles are 8 bytes
@@ -1898,6 +2006,7 @@
}
public final void readDoubleArray(@NonNull double[] val) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -1909,20 +2018,24 @@
}
public final void writeStringArray(@Nullable String[] val) {
+ assertNotRecycled();
writeString16Array(val);
}
@Nullable
public final String[] createStringArray() {
+ assertNotRecycled();
return createString16Array();
}
public final void readStringArray(@NonNull String[] val) {
+ assertNotRecycled();
readString16Array(val);
}
/** {@hide} */
public final void writeString8Array(@Nullable String[] val) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -1937,6 +2050,7 @@
/** {@hide} */
@Nullable
public final String[] createString8Array() {
+ assertNotRecycled();
int N = readInt();
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
if (N >= 0) {
@@ -1952,6 +2066,7 @@
/** {@hide} */
public final void readString8Array(@NonNull String[] val) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -1964,6 +2079,7 @@
/** {@hide} */
public final void writeString16Array(@Nullable String[] val) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -1978,6 +2094,7 @@
/** {@hide} */
@Nullable
public final String[] createString16Array() {
+ assertNotRecycled();
int N = readInt();
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
if (N >= 0) {
@@ -1993,6 +2110,7 @@
/** {@hide} */
public final void readString16Array(@NonNull String[] val) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -2004,6 +2122,7 @@
}
public final void writeBinderArray(@Nullable IBinder[] val) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -2028,6 +2147,7 @@
*/
public final <T extends IInterface> void writeInterfaceArray(
@SuppressLint("ArrayReturn") @Nullable T[] val) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -2043,6 +2163,7 @@
* @hide
*/
public final void writeCharSequenceArray(@Nullable CharSequence[] val) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -2058,6 +2179,7 @@
* @hide
*/
public final void writeCharSequenceList(@Nullable ArrayList<CharSequence> val) {
+ assertNotRecycled();
if (val != null) {
int N = val.size();
writeInt(N);
@@ -2071,6 +2193,7 @@
@Nullable
public final IBinder[] createBinderArray() {
+ assertNotRecycled();
int N = readInt();
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
if (N >= 0) {
@@ -2085,6 +2208,7 @@
}
public final void readBinderArray(@NonNull IBinder[] val) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -2106,6 +2230,7 @@
@Nullable
public final <T extends IInterface> T[] createInterfaceArray(
@NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) {
+ assertNotRecycled();
int N = readInt();
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
if (N >= 0) {
@@ -2130,6 +2255,7 @@
public final <T extends IInterface> void readInterfaceArray(
@SuppressLint("ArrayReturn") @NonNull T[] val,
@NonNull Function<IBinder, T> asInterface) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -2155,6 +2281,7 @@
* @see Parcelable
*/
public final <T extends Parcelable> void writeTypedList(@Nullable List<T> val) {
+ assertNotRecycled();
writeTypedList(val, 0);
}
@@ -2174,6 +2301,7 @@
*/
public final <T extends Parcelable> void writeTypedSparseArray(@Nullable SparseArray<T> val,
int parcelableFlags) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -2203,6 +2331,7 @@
* @see Parcelable
*/
public <T extends Parcelable> void writeTypedList(@Nullable List<T> val, int parcelableFlags) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -2228,6 +2357,7 @@
* @see #readStringList
*/
public final void writeStringList(@Nullable List<String> val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -2253,6 +2383,7 @@
* @see #readBinderList
*/
public final void writeBinderList(@Nullable List<IBinder> val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -2275,6 +2406,7 @@
* @see #readInterfaceList
*/
public final <T extends IInterface> void writeInterfaceList(@Nullable List<T> val) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -2296,6 +2428,7 @@
* @see #readParcelableList(List, ClassLoader)
*/
public final <T extends Parcelable> void writeParcelableList(@Nullable List<T> val, int flags) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -2330,6 +2463,7 @@
*/
public final <T extends Parcelable> void writeTypedArray(@Nullable T[] val,
int parcelableFlags) {
+ assertNotRecycled();
if (val != null) {
int N = val.length;
writeInt(N);
@@ -2352,6 +2486,7 @@
*/
public final <T extends Parcelable> void writeTypedObject(@Nullable T val,
int parcelableFlags) {
+ assertNotRecycled();
if (val != null) {
writeInt(1);
val.writeToParcel(this, parcelableFlags);
@@ -2389,6 +2524,7 @@
*/
public <T> void writeFixedArray(@Nullable T val, int parcelableFlags,
@NonNull int... dimensions) {
+ assertNotRecycled();
if (val == null) {
writeInt(-1);
return;
@@ -2500,6 +2636,7 @@
* should be used).</p>
*/
public final void writeValue(@Nullable Object v) {
+ assertNotRecycled();
if (v instanceof LazyValue) {
LazyValue value = (LazyValue) v;
value.writeToParcel(this);
@@ -2617,6 +2754,7 @@
* @hide
*/
public void writeValue(int type, @Nullable Object v) {
+ assertNotRecycled();
switch (type) {
case VAL_NULL:
break;
@@ -2730,6 +2868,7 @@
* {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}.
*/
public final void writeParcelable(@Nullable Parcelable p, int parcelableFlags) {
+ assertNotRecycled();
if (p == null) {
writeString(null);
return;
@@ -2745,6 +2884,7 @@
* @see #readParcelableCreator
*/
public final void writeParcelableCreator(@NonNull Parcelable p) {
+ assertNotRecycled();
String name = p.getClass().getName();
writeString(name);
}
@@ -2783,6 +2923,7 @@
*/
@TestApi
public boolean allowSquashing() {
+ assertNotRecycled();
boolean previous = mAllowSquashing;
mAllowSquashing = true;
return previous;
@@ -2794,6 +2935,7 @@
*/
@TestApi
public void restoreAllowSquashing(boolean previous) {
+ assertNotRecycled();
mAllowSquashing = previous;
if (!mAllowSquashing) {
mWrittenSquashableParcelables = null;
@@ -2850,6 +2992,7 @@
* @hide
*/
public boolean maybeWriteSquashed(@NonNull Parcelable p) {
+ assertNotRecycled();
if (!mAllowSquashing) {
// Don't squash, and don't put it in the map either.
writeInt(0);
@@ -2900,6 +3043,7 @@
@SuppressWarnings("unchecked")
@Nullable
public <T extends Parcelable> T readSquashed(SquashReadHelper<T> reader) {
+ assertNotRecycled();
final int offset = readInt();
final int pos = dataPosition();
@@ -2933,6 +3077,7 @@
* using the other approaches to writing data in to a Parcel.
*/
public final void writeSerializable(@Nullable Serializable s) {
+ assertNotRecycled();
if (s == null) {
writeString(null);
return;
@@ -2985,6 +3130,7 @@
*/
@RavenwoodReplace(blockedBy = AppOpsManager.class)
public final void writeException(@NonNull Exception e) {
+ assertNotRecycled();
AppOpsManager.prefixParcelWithAppOpsIfNeeded(this);
int code = getExceptionCode(e);
@@ -3065,6 +3211,7 @@
/** @hide */
public void writeStackTrace(@NonNull Throwable e) {
+ assertNotRecycled();
final int sizePosition = dataPosition();
writeInt(0); // Header size will be filled in later
StackTraceElement[] stackTrace = e.getStackTrace();
@@ -3090,6 +3237,7 @@
*/
@RavenwoodReplace(blockedBy = AppOpsManager.class)
public final void writeNoException() {
+ assertNotRecycled();
AppOpsManager.prefixParcelWithAppOpsIfNeeded(this);
// Despite the name of this function ("write no exception"),
@@ -3133,6 +3281,7 @@
* @see #writeNoException
*/
public final void readException() {
+ assertNotRecycled();
int code = readExceptionCode();
if (code != 0) {
String msg = readString();
@@ -3156,6 +3305,7 @@
@UnsupportedAppUsage
@TestApi
public final int readExceptionCode() {
+ assertNotRecycled();
int code = readInt();
if (code == EX_HAS_NOTED_APPOPS_REPLY_HEADER) {
AppOpsManager.readAndLogNotedAppops(this);
@@ -3189,6 +3339,7 @@
* @param msg The exception message.
*/
public final void readException(int code, String msg) {
+ assertNotRecycled();
String remoteStackTrace = null;
final int remoteStackPayloadSize = readInt();
if (remoteStackPayloadSize > 0) {
@@ -3219,6 +3370,7 @@
/** @hide */
public Exception createExceptionOrNull(int code, String msg) {
+ assertNotRecycled();
switch (code) {
case EX_PARCELABLE:
if (readInt() > 0) {
@@ -3251,6 +3403,7 @@
* Read an integer value from the parcel at the current dataPosition().
*/
public final int readInt() {
+ assertNotRecycled();
return nativeReadInt(mNativePtr);
}
@@ -3258,6 +3411,7 @@
* Read a long integer value from the parcel at the current dataPosition().
*/
public final long readLong() {
+ assertNotRecycled();
return nativeReadLong(mNativePtr);
}
@@ -3266,6 +3420,7 @@
* dataPosition().
*/
public final float readFloat() {
+ assertNotRecycled();
return nativeReadFloat(mNativePtr);
}
@@ -3274,6 +3429,7 @@
* current dataPosition().
*/
public final double readDouble() {
+ assertNotRecycled();
return nativeReadDouble(mNativePtr);
}
@@ -3282,16 +3438,19 @@
*/
@Nullable
public final String readString() {
+ assertNotRecycled();
return readString16();
}
/** {@hide} */
public final @Nullable String readString8() {
+ assertNotRecycled();
return mReadWriteHelper.readString8(this);
}
/** {@hide} */
public final @Nullable String readString16() {
+ assertNotRecycled();
return mReadWriteHelper.readString16(this);
}
@@ -3303,16 +3462,19 @@
* @hide
*/
public @Nullable String readStringNoHelper() {
+ assertNotRecycled();
return readString16NoHelper();
}
/** {@hide} */
public @Nullable String readString8NoHelper() {
+ assertNotRecycled();
return nativeReadString8(mNativePtr);
}
/** {@hide} */
public @Nullable String readString16NoHelper() {
+ assertNotRecycled();
return nativeReadString16(mNativePtr);
}
@@ -3320,6 +3482,7 @@
* Read a boolean value from the parcel at the current dataPosition().
*/
public final boolean readBoolean() {
+ assertNotRecycled();
return readInt() != 0;
}
@@ -3330,6 +3493,7 @@
@UnsupportedAppUsage
@Nullable
public final CharSequence readCharSequence() {
+ assertNotRecycled();
return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(this);
}
@@ -3337,6 +3501,7 @@
* Read an object from the parcel at the current dataPosition().
*/
public final IBinder readStrongBinder() {
+ assertNotRecycled();
final IBinder result = nativeReadStrongBinder(mNativePtr);
// If it's a reply from a method with @PropagateAllowBlocking, then inherit allow-blocking
@@ -3352,6 +3517,7 @@
* Read a FileDescriptor from the parcel at the current dataPosition().
*/
public final ParcelFileDescriptor readFileDescriptor() {
+ assertNotRecycled();
FileDescriptor fd = nativeReadFileDescriptor(mNativePtr);
return fd != null ? new ParcelFileDescriptor(fd) : null;
}
@@ -3359,6 +3525,7 @@
/** {@hide} */
@UnsupportedAppUsage
public final FileDescriptor readRawFileDescriptor() {
+ assertNotRecycled();
return nativeReadFileDescriptor(mNativePtr);
}
@@ -3369,6 +3536,7 @@
**/
@Nullable
public final FileDescriptor[] createRawFileDescriptorArray() {
+ assertNotRecycled();
int N = readInt();
if (N < 0) {
return null;
@@ -3388,6 +3556,7 @@
* @return the FileDescriptor array, or null if the array is null.
**/
public final void readRawFileDescriptorArray(FileDescriptor[] val) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -3402,6 +3571,7 @@
* Read a byte value from the parcel at the current dataPosition().
*/
public final byte readByte() {
+ assertNotRecycled();
return (byte)(readInt() & 0xff);
}
@@ -3416,6 +3586,7 @@
*/
@Deprecated
public final void readMap(@NonNull Map outVal, @Nullable ClassLoader loader) {
+ assertNotRecycled();
readMapInternal(outVal, loader, /* clazzKey */ null, /* clazzValue */ null);
}
@@ -3429,6 +3600,7 @@
public <K, V> void readMap(@NonNull Map<? super K, ? super V> outVal,
@Nullable ClassLoader loader, @NonNull Class<K> clazzKey,
@NonNull Class<V> clazzValue) {
+ assertNotRecycled();
Objects.requireNonNull(clazzKey);
Objects.requireNonNull(clazzValue);
readMapInternal(outVal, loader, clazzKey, clazzValue);
@@ -3447,6 +3619,7 @@
*/
@Deprecated
public final void readList(@NonNull List outVal, @Nullable ClassLoader loader) {
+ assertNotRecycled();
int N = readInt();
readListInternal(outVal, N, loader, /* clazz */ null);
}
@@ -3468,6 +3641,7 @@
*/
public <T> void readList(@NonNull List<? super T> outVal,
@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+ assertNotRecycled();
Objects.requireNonNull(clazz);
int n = readInt();
readListInternal(outVal, n, loader, clazz);
@@ -3487,6 +3661,7 @@
@Deprecated
@Nullable
public HashMap readHashMap(@Nullable ClassLoader loader) {
+ assertNotRecycled();
return readHashMapInternal(loader, /* clazzKey */ null, /* clazzValue */ null);
}
@@ -3501,6 +3676,7 @@
@Nullable
public <K, V> HashMap<K, V> readHashMap(@Nullable ClassLoader loader,
@NonNull Class<? extends K> clazzKey, @NonNull Class<? extends V> clazzValue) {
+ assertNotRecycled();
Objects.requireNonNull(clazzKey);
Objects.requireNonNull(clazzValue);
return readHashMapInternal(loader, clazzKey, clazzValue);
@@ -3513,6 +3689,7 @@
*/
@Nullable
public final Bundle readBundle() {
+ assertNotRecycled();
return readBundle(null);
}
@@ -3524,6 +3701,7 @@
*/
@Nullable
public final Bundle readBundle(@Nullable ClassLoader loader) {
+ assertNotRecycled();
int length = readInt();
if (length < 0) {
if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length);
@@ -3544,6 +3722,7 @@
*/
@Nullable
public final PersistableBundle readPersistableBundle() {
+ assertNotRecycled();
return readPersistableBundle(null);
}
@@ -3555,6 +3734,7 @@
*/
@Nullable
public final PersistableBundle readPersistableBundle(@Nullable ClassLoader loader) {
+ assertNotRecycled();
int length = readInt();
if (length < 0) {
if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length);
@@ -3573,6 +3753,7 @@
*/
@NonNull
public final Size readSize() {
+ assertNotRecycled();
final int width = readInt();
final int height = readInt();
return new Size(width, height);
@@ -3583,6 +3764,7 @@
*/
@NonNull
public final SizeF readSizeF() {
+ assertNotRecycled();
final float width = readFloat();
final float height = readFloat();
return new SizeF(width, height);
@@ -3593,6 +3775,7 @@
*/
@Nullable
public final byte[] createByteArray() {
+ assertNotRecycled();
return nativeCreateByteArray(mNativePtr);
}
@@ -3601,6 +3784,7 @@
* given byte array.
*/
public final void readByteArray(@NonNull byte[] val) {
+ assertNotRecycled();
boolean valid = nativeReadByteArray(mNativePtr, val, (val != null) ? val.length : 0);
if (!valid) {
throw new RuntimeException("bad array lengths");
@@ -3613,6 +3797,7 @@
*/
@Nullable
public final byte[] readBlob() {
+ assertNotRecycled();
return nativeReadBlob(mNativePtr);
}
@@ -3623,6 +3808,7 @@
@UnsupportedAppUsage
@Nullable
public final String[] readStringArray() {
+ assertNotRecycled();
return createString16Array();
}
@@ -3632,6 +3818,7 @@
*/
@Nullable
public final CharSequence[] readCharSequenceArray() {
+ assertNotRecycled();
CharSequence[] array = null;
int length = readInt();
@@ -3654,6 +3841,7 @@
*/
@Nullable
public final ArrayList<CharSequence> readCharSequenceList() {
+ assertNotRecycled();
ArrayList<CharSequence> array = null;
int length = readInt();
@@ -3683,6 +3871,7 @@
@Deprecated
@Nullable
public ArrayList readArrayList(@Nullable ClassLoader loader) {
+ assertNotRecycled();
return readArrayListInternal(loader, /* clazz */ null);
}
@@ -3705,6 +3894,7 @@
@Nullable
public <T> ArrayList<T> readArrayList(@Nullable ClassLoader loader,
@NonNull Class<? extends T> clazz) {
+ assertNotRecycled();
Objects.requireNonNull(clazz);
return readArrayListInternal(loader, clazz);
}
@@ -3724,6 +3914,7 @@
@Deprecated
@Nullable
public Object[] readArray(@Nullable ClassLoader loader) {
+ assertNotRecycled();
return readArrayInternal(loader, /* clazz */ null);
}
@@ -3745,6 +3936,7 @@
@SuppressLint({"ArrayReturn", "NullableCollection"})
@Nullable
public <T> T[] readArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+ assertNotRecycled();
Objects.requireNonNull(clazz);
return readArrayInternal(loader, clazz);
}
@@ -3764,6 +3956,7 @@
@Deprecated
@Nullable
public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) {
+ assertNotRecycled();
return readSparseArrayInternal(loader, /* clazz */ null);
}
@@ -3785,6 +3978,7 @@
@Nullable
public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader,
@NonNull Class<? extends T> clazz) {
+ assertNotRecycled();
Objects.requireNonNull(clazz);
return readSparseArrayInternal(loader, clazz);
}
@@ -3796,6 +3990,7 @@
*/
@Nullable
public final SparseBooleanArray readSparseBooleanArray() {
+ assertNotRecycled();
int N = readInt();
if (N < 0) {
return null;
@@ -3812,6 +4007,7 @@
*/
@Nullable
public final SparseIntArray readSparseIntArray() {
+ assertNotRecycled();
int N = readInt();
if (N < 0) {
return null;
@@ -3836,6 +4032,7 @@
*/
@Nullable
public final <T> ArrayList<T> createTypedArrayList(@NonNull Parcelable.Creator<T> c) {
+ assertNotRecycled();
int N = readInt();
if (N < 0) {
return null;
@@ -3859,6 +4056,7 @@
* @see #writeTypedList
*/
public final <T> void readTypedList(@NonNull List<T> list, @NonNull Parcelable.Creator<T> c) {
+ assertNotRecycled();
int M = list.size();
int N = readInt();
int i = 0;
@@ -3888,6 +4086,7 @@
*/
public final @Nullable <T extends Parcelable> SparseArray<T> createTypedSparseArray(
@NonNull Parcelable.Creator<T> creator) {
+ assertNotRecycled();
final int count = readInt();
if (count < 0) {
return null;
@@ -3917,6 +4116,7 @@
*/
public final @Nullable <T extends Parcelable> ArrayMap<String, T> createTypedArrayMap(
@NonNull Parcelable.Creator<T> creator) {
+ assertNotRecycled();
final int count = readInt();
if (count < 0) {
return null;
@@ -3944,6 +4144,7 @@
*/
@Nullable
public final ArrayList<String> createStringArrayList() {
+ assertNotRecycled();
int N = readInt();
if (N < 0) {
return null;
@@ -3970,6 +4171,7 @@
*/
@Nullable
public final ArrayList<IBinder> createBinderArrayList() {
+ assertNotRecycled();
int N = readInt();
if (N < 0) {
return null;
@@ -3997,6 +4199,7 @@
@Nullable
public final <T extends IInterface> ArrayList<T> createInterfaceArrayList(
@NonNull Function<IBinder, T> asInterface) {
+ assertNotRecycled();
int N = readInt();
if (N < 0) {
return null;
@@ -4017,6 +4220,7 @@
* @see #writeStringList
*/
public final void readStringList(@NonNull List<String> list) {
+ assertNotRecycled();
int M = list.size();
int N = readInt();
int i = 0;
@@ -4038,6 +4242,7 @@
* @see #writeBinderList
*/
public final void readBinderList(@NonNull List<IBinder> list) {
+ assertNotRecycled();
int M = list.size();
int N = readInt();
int i = 0;
@@ -4060,6 +4265,7 @@
*/
public final <T extends IInterface> void readInterfaceList(@NonNull List<T> list,
@NonNull Function<IBinder, T> asInterface) {
+ assertNotRecycled();
int M = list.size();
int N = readInt();
int i = 0;
@@ -4091,6 +4297,7 @@
@NonNull
public final <T extends Parcelable> List<T> readParcelableList(@NonNull List<T> list,
@Nullable ClassLoader cl) {
+ assertNotRecycled();
return readParcelableListInternal(list, cl, /*clazz*/ null);
}
@@ -4112,6 +4319,7 @@
@NonNull
public <T> List<T> readParcelableList(@NonNull List<T> list,
@Nullable ClassLoader cl, @NonNull Class<? extends T> clazz) {
+ assertNotRecycled();
Objects.requireNonNull(list);
Objects.requireNonNull(clazz);
return readParcelableListInternal(list, cl, clazz);
@@ -4157,6 +4365,7 @@
*/
@Nullable
public final <T> T[] createTypedArray(@NonNull Parcelable.Creator<T> c) {
+ assertNotRecycled();
int N = readInt();
if (N < 0) {
return null;
@@ -4170,6 +4379,7 @@
}
public final <T> void readTypedArray(@NonNull T[] val, @NonNull Parcelable.Creator<T> c) {
+ assertNotRecycled();
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
@@ -4186,6 +4396,7 @@
*/
@Deprecated
public final <T> T[] readTypedArray(Parcelable.Creator<T> c) {
+ assertNotRecycled();
return createTypedArray(c);
}
@@ -4202,6 +4413,7 @@
*/
@Nullable
public final <T> T readTypedObject(@NonNull Parcelable.Creator<T> c) {
+ assertNotRecycled();
if (readInt() != 0) {
return c.createFromParcel(this);
} else {
@@ -4228,6 +4440,7 @@
* @see #readTypedArray
*/
public <T> void readFixedArray(@NonNull T val) {
+ assertNotRecycled();
Class<?> componentType = val.getClass().getComponentType();
if (componentType == boolean.class) {
readBooleanArray((boolean[]) val);
@@ -4268,6 +4481,7 @@
*/
public <T, S extends IInterface> void readFixedArray(@NonNull T val,
@NonNull Function<IBinder, S> asInterface) {
+ assertNotRecycled();
Class<?> componentType = val.getClass().getComponentType();
if (IInterface.class.isAssignableFrom(componentType)) {
readInterfaceArray((S[]) val, asInterface);
@@ -4294,6 +4508,7 @@
*/
public <T, S extends Parcelable> void readFixedArray(@NonNull T val,
@NonNull Parcelable.Creator<S> c) {
+ assertNotRecycled();
Class<?> componentType = val.getClass().getComponentType();
if (Parcelable.class.isAssignableFrom(componentType)) {
readTypedArray((S[]) val, c);
@@ -4351,6 +4566,7 @@
*/
@Nullable
public <T> T createFixedArray(@NonNull Class<T> cls, @NonNull int... dimensions) {
+ assertNotRecycled();
// Check if type matches with dimensions
// If type is one-dimensional array, delegate to other creators
// Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
@@ -4424,6 +4640,7 @@
@Nullable
public <T, S extends IInterface> T createFixedArray(@NonNull Class<T> cls,
@NonNull Function<IBinder, S> asInterface, @NonNull int... dimensions) {
+ assertNotRecycled();
// Check if type matches with dimensions
// If type is one-dimensional array, delegate to other creators
// Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
@@ -4484,6 +4701,7 @@
@Nullable
public <T, S extends Parcelable> T createFixedArray(@NonNull Class<T> cls,
@NonNull Parcelable.Creator<S> c, @NonNull int... dimensions) {
+ assertNotRecycled();
// Check if type matches with dimensions
// If type is one-dimensional array, delegate to other creators
// Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
@@ -4547,6 +4765,7 @@
*/
public final <T extends Parcelable> void writeParcelableArray(@Nullable T[] value,
int parcelableFlags) {
+ assertNotRecycled();
if (value != null) {
int N = value.length;
writeInt(N);
@@ -4565,6 +4784,7 @@
*/
@Nullable
public final Object readValue(@Nullable ClassLoader loader) {
+ assertNotRecycled();
return readValue(loader, /* clazz */ null);
}
@@ -4620,6 +4840,7 @@
*/
@Nullable
public Object readLazyValue(@Nullable ClassLoader loader) {
+ assertNotRecycled();
int start = dataPosition();
int type = readInt();
if (isLengthPrefixed(type)) {
@@ -5022,6 +5243,7 @@
@Deprecated
@Nullable
public final <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader) {
+ assertNotRecycled();
return readParcelableInternal(loader, /* clazz */ null);
}
@@ -5041,6 +5263,7 @@
*/
@Nullable
public <T> T readParcelable(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+ assertNotRecycled();
Objects.requireNonNull(clazz);
return readParcelableInternal(loader, clazz);
}
@@ -5069,6 +5292,7 @@
@Nullable
public final <T extends Parcelable> T readCreator(@NonNull Parcelable.Creator<?> creator,
@Nullable ClassLoader loader) {
+ assertNotRecycled();
if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
Parcelable.ClassLoaderCreator<?> classLoaderCreator =
(Parcelable.ClassLoaderCreator<?>) creator;
@@ -5096,6 +5320,7 @@
@Deprecated
@Nullable
public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
+ assertNotRecycled();
return readParcelableCreatorInternal(loader, /* clazz */ null);
}
@@ -5116,6 +5341,7 @@
@Nullable
public <T> Parcelable.Creator<T> readParcelableCreator(
@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+ assertNotRecycled();
Objects.requireNonNull(clazz);
return readParcelableCreatorInternal(loader, clazz);
}
@@ -5238,6 +5464,7 @@
@Deprecated
@Nullable
public Parcelable[] readParcelableArray(@Nullable ClassLoader loader) {
+ assertNotRecycled();
return readParcelableArrayInternal(loader, /* clazz */ null);
}
@@ -5258,6 +5485,7 @@
@SuppressLint({"ArrayReturn", "NullableCollection"})
@Nullable
public <T> T[] readParcelableArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+ assertNotRecycled();
return readParcelableArrayInternal(loader, requireNonNull(clazz));
}
@@ -5291,6 +5519,7 @@
@Deprecated
@Nullable
public Serializable readSerializable() {
+ assertNotRecycled();
return readSerializableInternal(/* loader */ null, /* clazz */ null);
}
@@ -5307,6 +5536,7 @@
*/
@Nullable
public <T> T readSerializable(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+ assertNotRecycled();
Objects.requireNonNull(clazz);
return readSerializableInternal(
loader == null ? getClass().getClassLoader() : loader, clazz);
@@ -5548,6 +5778,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void readArrayMap(@NonNull ArrayMap<? super String, Object> outVal,
@Nullable ClassLoader loader) {
+ assertNotRecycled();
final int N = readInt();
if (N < 0) {
return;
@@ -5564,6 +5795,7 @@
*/
@UnsupportedAppUsage
public @Nullable ArraySet<? extends Object> readArraySet(@Nullable ClassLoader loader) {
+ assertNotRecycled();
final int size = readInt();
if (size < 0) {
return null;
@@ -5703,6 +5935,7 @@
* @hide For testing
*/
public long getOpenAshmemSize() {
+ assertNotRecycled();
return nativeGetOpenAshmemSize(mNativePtr);
}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index c2b8157..57e1b58 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -474,3 +474,12 @@
description: "Enable cross-user roles platform API"
bug: "367732307"
}
+
+flag {
+ name: "rate_limit_batched_note_op_async_callbacks_enabled"
+ is_fixed_read_only: true
+ is_exported: true
+ namespace: "permissions"
+ description: "Rate limit async noteOp callbacks for batched noteOperation binder call"
+ bug: "366013082"
+}
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 269839b..2d922b4 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -15,9 +15,12 @@
*/
package android.service.autofill;
+import static android.service.autofill.Flags.FLAG_AUTOFILL_SESSION_DESTROYED;
+
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.CallSuper;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
@@ -669,6 +672,14 @@
AutofillService.this,
new SavedDatasetsInfoCallbackImpl(receiver, SavedDatasetsInfo.TYPE_PASSWORDS)));
}
+
+ @Override
+ public void onSessionDestroyed(@Nullable FillEventHistory history) {
+ mHandler.sendMessage(obtainMessage(
+ AutofillService::onSessionDestroyed,
+ AutofillService.this,
+ history));
+ }
};
private Handler mHandler;
@@ -783,26 +794,42 @@
}
/**
- * Gets the events that happened after the last
- * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
+ * Called when an Autofill context has ended and the Autofill session is finished. This will be
+ * called as the last step of the Autofill lifecycle described in {@link AutofillManager}.
+ *
+ * <p>This will also contain the finished Session's FillEventHistory, so providers do not need
+ * to explicitly call {@link #getFillEventHistory()}
+ *
+ * <p>This will usually happens whenever {@link AutofillManager#commit()} or {@link
+ * AutofillManager#cancel()} is called.
+ */
+ @FlaggedApi(FLAG_AUTOFILL_SESSION_DESTROYED)
+ public void onSessionDestroyed(@Nullable FillEventHistory history) {}
+
+ /**
+ * Gets the events that happened after the last {@link
+ * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
* call.
*
* <p>This method is typically used to keep track of previous user actions to optimize further
* requests. For example, the service might return email addresses in alphabetical order by
* default, but change that order based on the address the user picked on previous requests.
*
- * <p>The history is not persisted over reboots, and it's cleared every time the service
- * replies to a {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} by calling
- * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)}
- * (if the service doesn't call any of these methods, the history will clear out after some
- * pre-defined time). Hence, the service should call {@link #getFillEventHistory()} before
- * finishing the {@link FillCallback}.
+ * <p>The history is not persisted over reboots, and it's cleared every time the service replies
+ * to a {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} by calling {@link
+ * FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)} (if the
+ * service doesn't call any of these methods, the history will clear out after some pre-defined
+ * time). Hence, the service should call {@link #getFillEventHistory()} before finishing the
+ * {@link FillCallback}.
*
* @return The history or {@code null} if there are no events.
- *
* @throws RuntimeException if the event history could not be retrieved.
+ * @deprecated Use {@link #onSessionDestroyed(FillEventHistory) instead}
*/
- @Nullable public final FillEventHistory getFillEventHistory() {
+ @FlaggedApi(FLAG_AUTOFILL_SESSION_DESTROYED)
+ @Deprecated
+ @Nullable
+ public final FillEventHistory getFillEventHistory() {
final AutofillManager afm = getSystemService(AutofillManager.class);
if (afm == null) {
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index 3b64b8a..71b75e7 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -25,6 +25,8 @@
import android.service.autofill.SaveRequest;
import com.android.internal.os.IResultReceiver;
+parcelable FillEventHistory;
+
/**
* Interface from the system to an auto fill service.
*
@@ -38,4 +40,5 @@
void onSaveRequest(in SaveRequest request, in ISaveCallback callback);
void onSavedPasswordCountRequest(in IResultReceiver receiver);
void onConvertCredentialRequest(in ConvertCredentialRequest convertCredentialRequest, in IConvertCredentialCallback convertCredentialCallback);
+ void onSessionDestroyed(in FillEventHistory history);
}
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index bb233d2..3ff5f95 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -286,7 +286,7 @@
* @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
* timebase.
* @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
- * @param modeId The new mode Id
+ * @param modeId The new mode ID
* @param renderPeriod The render frame period, which is a multiple of the mode's vsync period
*/
public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId,
@@ -294,6 +294,15 @@
}
/**
+ * Called when a display mode rejection event is received.
+ *
+ * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
+ * @param modeId The mode ID of the mode that was rejected
+ */
+ public void onModeRejected(long physicalDisplayId, int modeId) {
+ }
+
+ /**
* Called when a display hdcp levels change event is received.
*
* @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
@@ -386,6 +395,12 @@
// Called from native code.
@SuppressWarnings("unused")
+ private void dispatchModeRejected(long physicalDisplayId, int modeId) {
+ onModeRejected(physicalDisplayId, modeId);
+ }
+
+ // Called from native code.
+ @SuppressWarnings("unused")
private void dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId,
FrameRateOverride[] overrides) {
onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides);
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index 641b010..f6fdec9 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -142,4 +142,12 @@
description: "Recover from buffer stuffing when SurfaceFlinger misses a frame"
bug: "294922229"
is_fixed_read_only: true
-}
\ No newline at end of file
+}
+
+flag {
+ name: "date_time_view_relative_time_display_configs"
+ namespace: "systemui"
+ description: "Enables DateTimeView to use additional display configurations for relative time"
+ bug: "364653005"
+ is_fixed_read_only: true
+}
diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java
index 41ff69d..143b4b7 100644
--- a/core/java/android/widget/DateTimeView.java
+++ b/core/java/android/widget/DateTimeView.java
@@ -21,6 +21,7 @@
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.YEAR_IN_MILLIS;
+import android.annotation.IntDef;
import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
@@ -41,6 +42,8 @@
import com.android.internal.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.text.DateFormat;
import java.time.Instant;
import java.time.LocalDate;
@@ -70,6 +73,23 @@
private static final int SHOW_TIME = 0;
private static final int SHOW_MONTH_DAY_YEAR = 1;
+ /** @hide */
+ @IntDef(value = {UNIT_DISPLAY_LENGTH_SHORTEST, UNIT_DISPLAY_LENGTH_MEDIUM})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface UnitDisplayLength {}
+ public static final int UNIT_DISPLAY_LENGTH_SHORTEST = 0;
+ public static final int UNIT_DISPLAY_LENGTH_MEDIUM = 1;
+
+ /** @hide */
+ @IntDef(flag = true, value = {DISAMBIGUATION_TEXT_PAST, DISAMBIGUATION_TEXT_FUTURE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DisambiguationTextMask {}
+ public static final int DISAMBIGUATION_TEXT_PAST = 0x01;
+ public static final int DISAMBIGUATION_TEXT_FUTURE = 0x02;
+
+ private final boolean mCanUseRelativeTimeDisplayConfigs =
+ android.view.flags.Flags.dateTimeViewRelativeTimeDisplayConfigs();
+
private long mTimeMillis;
// The LocalDateTime equivalent of mTimeMillis but truncated to minute, i.e. no seconds / nanos.
private LocalDateTime mLocalTime;
@@ -81,6 +101,8 @@
private static final ThreadLocal<ReceiverInfo> sReceiverInfo = new ThreadLocal<ReceiverInfo>();
private String mNowText;
private boolean mShowRelativeTime;
+ private int mRelativeTimeDisambiguationTextMask;
+ private int mRelativeTimeUnitDisplayLength = UNIT_DISPLAY_LENGTH_SHORTEST;
public DateTimeView(Context context) {
this(context, null);
@@ -89,20 +111,23 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public DateTimeView(Context context, AttributeSet attrs) {
super(context, attrs);
- final TypedArray a = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.DateTimeView, 0,
- 0);
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.DateTimeView, 0, 0);
- final int N = a.getIndexCount();
- for (int i = 0; i < N; i++) {
- int attr = a.getIndex(i);
- switch (attr) {
- case R.styleable.DateTimeView_showRelative:
- boolean relative = a.getBoolean(i, false);
- setShowRelativeTime(relative);
- break;
- }
+ setShowRelativeTime(a.getBoolean(R.styleable.DateTimeView_showRelative, false));
+ if (mCanUseRelativeTimeDisplayConfigs) {
+ setRelativeTimeDisambiguationTextMask(
+ a.getInt(
+ R.styleable.DateTimeView_relativeTimeDisambiguationText,
+ // The original implementation showed disambiguation text for future
+ // times only, so continue with that default.
+ DISAMBIGUATION_TEXT_FUTURE));
+ setRelativeTimeUnitDisplayLength(
+ a.getInt(
+ R.styleable.DateTimeView_relativeTimeUnitDisplayLength,
+ UNIT_DISPLAY_LENGTH_SHORTEST));
}
+
a.recycle();
}
@@ -150,6 +175,29 @@
update();
}
+ /** See {@link R.styleable.DateTimeView_relativeTimeDisambiguationText}. */
+ @android.view.RemotableViewMethod
+ public void setRelativeTimeDisambiguationTextMask(
+ @DisambiguationTextMask int disambiguationTextMask) {
+ if (!mCanUseRelativeTimeDisplayConfigs) {
+ return;
+ }
+ mRelativeTimeDisambiguationTextMask = disambiguationTextMask;
+ updateNowText();
+ update();
+ }
+
+ /** See {@link R.styleable.DateTimeView_relativeTimeUnitDisplayLength}. */
+ @android.view.RemotableViewMethod
+ public void setRelativeTimeUnitDisplayLength(@UnitDisplayLength int unitDisplayLength) {
+ if (!mCanUseRelativeTimeDisplayConfigs) {
+ return;
+ }
+ mRelativeTimeUnitDisplayLength = unitDisplayLength;
+ updateNowText();
+ update();
+ }
+
/**
* Returns whether this view shows relative time
*
@@ -264,17 +312,11 @@
return;
} else if (duration < HOUR_IN_MILLIS) {
count = (int)(duration / MINUTE_IN_MILLIS);
- result = getContext().getResources().getString(past
- ? com.android.internal.R.string.duration_minutes_shortest
- : com.android.internal.R.string.duration_minutes_shortest_future,
- count);
+ result = getContext().getResources().getString(getMinutesStringId(past), count);
millisIncrease = MINUTE_IN_MILLIS;
} else if (duration < DAY_IN_MILLIS) {
count = (int)(duration / HOUR_IN_MILLIS);
- result = getContext().getResources().getString(past
- ? com.android.internal.R.string.duration_hours_shortest
- : com.android.internal.R.string.duration_hours_shortest_future,
- count);
+ result = getContext().getResources().getString(getHoursStringId(past), count);
millisIncrease = HOUR_IN_MILLIS;
} else if (duration < YEAR_IN_MILLIS) {
// In weird cases it can become 0 because of daylight savings
@@ -283,10 +325,7 @@
LocalDateTime localNow = toLocalDateTime(now, zoneId);
count = Math.max(Math.abs(dayDistance(localDateTime, localNow)), 1);
- result = getContext().getResources().getString(past
- ? com.android.internal.R.string.duration_days_shortest
- : com.android.internal.R.string.duration_days_shortest_future,
- count);
+ result = getContext().getResources().getString(getDaysStringId(past), count);
if (past || count != 1) {
mUpdateTimeMillis = computeNextMidnight(localNow, zoneId);
millisIncrease = -1;
@@ -296,10 +335,7 @@
} else {
count = (int)(duration / YEAR_IN_MILLIS);
- result = getContext().getResources().getString(past
- ? com.android.internal.R.string.duration_years_shortest
- : com.android.internal.R.string.duration_years_shortest_future,
- count);
+ result = getContext().getResources().getString(getYearsStringId(past), count);
millisIncrease = YEAR_IN_MILLIS;
}
if (millisIncrease != -1) {
@@ -312,6 +348,139 @@
maybeSetText(result);
}
+ private int getMinutesStringId(boolean past) {
+ if (!mCanUseRelativeTimeDisplayConfigs) {
+ return past
+ ? com.android.internal.R.string.duration_minutes_shortest
+ : com.android.internal.R.string.duration_minutes_shortest_future;
+ }
+
+ if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
+ if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+ // "1m ago"
+ return com.android.internal.R.string.duration_minutes_shortest_past;
+ } else if (!past
+ && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+ // "in 1m"
+ return com.android.internal.R.string.duration_minutes_shortest_future;
+ } else {
+ // "1m"
+ return com.android.internal.R.string.duration_minutes_shortest;
+ }
+ } else { // UNIT_DISPLAY_LENGTH_MEDIUM
+ if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+ // "1min ago"
+ return com.android.internal.R.string.duration_minutes_medium_past;
+ } else if (!past
+ && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+ // "in 1min"
+ return com.android.internal.R.string.duration_minutes_medium_future;
+ } else {
+ // "1min"
+ return com.android.internal.R.string.duration_minutes_medium;
+ }
+ }
+ }
+
+ private int getHoursStringId(boolean past) {
+ if (!mCanUseRelativeTimeDisplayConfigs) {
+ return past
+ ? com.android.internal.R.string.duration_hours_shortest
+ : com.android.internal.R.string.duration_hours_shortest_future;
+ }
+ if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
+ if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+ // "1h ago"
+ return com.android.internal.R.string.duration_hours_shortest_past;
+ } else if (!past
+ && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+ // "in 1h"
+ return com.android.internal.R.string.duration_hours_shortest_future;
+ } else {
+ // "1h"
+ return com.android.internal.R.string.duration_hours_shortest;
+ }
+ } else { // UNIT_DISPLAY_LENGTH_MEDIUM
+ if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+ // "1hr ago"
+ return com.android.internal.R.string.duration_hours_medium_past;
+ } else if (!past
+ && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+ // "in 1hr"
+ return com.android.internal.R.string.duration_hours_medium_future;
+ } else {
+ // "1hr"
+ return com.android.internal.R.string.duration_hours_medium;
+ }
+ }
+ }
+
+ private int getDaysStringId(boolean past) {
+ if (!mCanUseRelativeTimeDisplayConfigs) {
+ return past
+ ? com.android.internal.R.string.duration_days_shortest
+ : com.android.internal.R.string.duration_days_shortest_future;
+ }
+ if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
+ if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+ // "1d ago"
+ return com.android.internal.R.string.duration_days_shortest_past;
+ } else if (!past
+ && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+ // "in 1d"
+ return com.android.internal.R.string.duration_days_shortest_future;
+ } else {
+ // "1d"
+ return com.android.internal.R.string.duration_days_shortest;
+ }
+ } else { // UNIT_DISPLAY_LENGTH_MEDIUM
+ if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+ // "1d ago"
+ return com.android.internal.R.string.duration_days_medium_past;
+ } else if (!past
+ && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+ // "in 1d"
+ return com.android.internal.R.string.duration_days_medium_future;
+ } else {
+ // "1d"
+ return com.android.internal.R.string.duration_days_medium;
+ }
+ }
+ }
+
+ private int getYearsStringId(boolean past) {
+ if (!mCanUseRelativeTimeDisplayConfigs) {
+ return past
+ ? com.android.internal.R.string.duration_years_shortest
+ : com.android.internal.R.string.duration_years_shortest_future;
+ }
+ if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
+ if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+ // "1y ago"
+ return com.android.internal.R.string.duration_years_shortest_past;
+ } else if (!past
+ && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+ // "in 1y"
+ return com.android.internal.R.string.duration_years_shortest_future;
+ } else {
+ // "1y"
+ return com.android.internal.R.string.duration_years_shortest;
+ }
+ } else { // UNIT_DISPLAY_LENGTH_MEDIUM
+ if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+ // "1y ago"
+ return com.android.internal.R.string.duration_years_medium_past;
+ } else if (!past
+ && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+ // "in 1y"
+ return com.android.internal.R.string.duration_years_medium_future;
+ } else {
+ // "1y"
+ return com.android.internal.R.string.duration_years_medium;
+ }
+ }
+ }
+
/**
* Sets text only if the text has actually changed. This prevents needles relayouts of this
* view when set to wrap_content.
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 2cfc680..f01aa80 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -163,4 +163,5 @@
void finishOperationForDevice(IBinder clientId, int code, int uid, String packageName,
@nullable String attributionTag, int virtualDeviceId);
List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(in int[] ops, String persistentDeviceId);
+ oneway void noteOperationsInBatch(in Map batchedNoteOps);
}
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index ee5bd65..644d699 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -70,6 +70,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.chooser.TargetInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -352,6 +353,7 @@
findViewById(R.id.use_same_profile_browser).setOnClickListener(v -> finish());
findViewById(R.id.button_open).setOnClickListener(v -> {
+ TargetInfo.refreshIntentCreatorToken(launchIntent);
startActivityAsCaller(
launchIntent,
ActivityOptions.makeCustomAnimation(
@@ -476,6 +478,7 @@
private void startActivityAsCaller(Intent newIntent, int userId) {
try {
+ TargetInfo.refreshIntentCreatorToken(newIntent);
startActivityAsCaller(
newIntent,
/* options= */ null,
@@ -502,6 +505,7 @@
return;
}
sanitizeIntent(innerIntent);
+ TargetInfo.refreshIntentCreatorToken(intentReceived);
startActivityAsCaller(intentReceived, null, false, getUserId());
finish();
}
@@ -525,6 +529,7 @@
if (singleTabOnly) {
intentReceived.putExtra(EXTRA_RESTRICT_TO_SINGLE_USER, true);
}
+ TargetInfo.refreshIntentCreatorToken(intentReceived);
startActivityAsCaller(intentReceived, null, false, userId);
finish();
}
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
index 473134e..0c65077 100644
--- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -173,6 +173,7 @@
@Override
public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, userId);
+ TargetInfo.refreshIntentCreatorToken(mResolvedIntent);
activity.startActivityAsCaller(mResolvedIntent, options, false, userId);
return true;
}
@@ -180,6 +181,7 @@
@Override
public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, user.getIdentifier());
+ TargetInfo.refreshIntentCreatorToken(mResolvedIntent);
activity.startActivityAsUser(mResolvedIntent, options, user);
return false;
}
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index d7f3a76..0eaa43d 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -260,6 +260,7 @@
intent.setComponent(mChooserTarget.getComponentName());
intent.putExtras(mChooserTarget.getIntentExtras());
TargetInfo.prepareIntentForCrossProfileLaunch(intent, userId);
+ TargetInfo.refreshIntentCreatorToken(intent);
// Important: we will ignore the target security checks in ActivityManager
// if and only if the ChooserTarget's target package is the same package
diff --git a/core/java/com/android/internal/app/chooser/TargetInfo.java b/core/java/com/android/internal/app/chooser/TargetInfo.java
index 7bb7ddc..fcf5883 100644
--- a/core/java/com/android/internal/app/chooser/TargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/TargetInfo.java
@@ -17,13 +17,17 @@
package com.android.internal.app.chooser;
+import static android.security.Flags.preventIntentRedirect;
+
import android.app.Activity;
+import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.RemoteException;
import android.os.UserHandle;
import com.android.internal.app.ResolverActivity;
@@ -141,4 +145,20 @@
intent.fixUris(currentUserId);
}
}
+
+ /**
+ * refreshes intent's creatorToken with its current intent key fields. This allows
+ * ChooserActivity to still keep original creatorToken's creator uid after making changes to
+ * the intent and still keep it valid.
+ * @param intent the intent's creatorToken needs to up refreshed.
+ */
+ static void refreshIntentCreatorToken(Intent intent) {
+ if (!preventIntentRedirect()) return;
+ try {
+ intent.setCreatorToken(ActivityManager.getService().refreshIntentCreatorToken(
+ intent.cloneForCreatorToken()));
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failure from system", e);
+ }
+ }
}
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 9b8551b..1e965c5d 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -85,51 +85,6 @@
}
/**
- * This is like <code>new byte[length]</code>, but it allocates the array as non-movable. This
- * prevents copies of the data from being left on the Java heap as a result of heap compaction.
- * Use this when the array will contain sensitive data such as a password or cryptographic key
- * that needs to be wiped from memory when no longer needed. The owner of the array is still
- * responsible for the zeroization; {@link #zeroize(byte[])} should be used to do so.
- *
- * @param length the length of the array to allocate
- * @return the new array
- */
- public static byte[] newNonMovableByteArray(int length) {
- return (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, length);
- }
-
- /**
- * Like {@link #newNonMovableByteArray(int)}, but allocates a char array.
- *
- * @param length the length of the array to allocate
- * @return the new array
- */
- public static char[] newNonMovableCharArray(int length) {
- return (char[]) VMRuntime.getRuntime().newNonMovableArray(char.class, length);
- }
-
- /**
- * Zeroizes a byte array as securely as possible. Use this when the array contains sensitive
- * data such as a password or cryptographic key.
- * <p>
- * This zeroizes the array in a way that is guaranteed to not be optimized out by the compiler.
- * If supported by the architecture, it zeroizes the data not just in the L1 data cache but also
- * in other levels of the memory hierarchy up to and including main memory (but not above that).
- * <p>
- * This works on any <code>byte[]</code>, but to ensure that copies of the array aren't left on
- * the Java heap the array should have been allocated with {@link #newNonMovableByteArray(int)}.
- * Use on other arrays might also introduce performance anomalies.
- *
- * @param array the array to zeroize
- */
- public static native void zeroize(byte[] array);
-
- /**
- * Like {@link #zeroize(byte[])}, but for char arrays.
- */
- public static native void zeroize(char[] array);
-
- /**
* Checks if the beginnings of two byte arrays are equal.
*
* @param array1 the first byte array
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 0ffe2f9..e22d958 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -92,7 +92,6 @@
"android_view_VelocityTracker.cpp",
"android_view_VerifiedKeyEvent.cpp",
"android_view_VerifiedMotionEvent.cpp",
- "com_android_internal_util_ArrayUtils.cpp",
"com_android_internal_util_VirtualRefBasePtr.cpp",
"core_jni_helpers.cpp",
":deviceproductinfoconstants_aidl",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 78d69f0..ac187b0 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -220,7 +220,6 @@
extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
extern int register_com_android_internal_security_VerityUtils(JNIEnv* env);
-extern int register_com_android_internal_util_ArrayUtils(JNIEnv* env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
extern int register_android_window_WindowInfosListener(JNIEnv* env);
extern int register_android_window_ScreenCapture(JNIEnv* env);
@@ -1622,7 +1621,6 @@
REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer),
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_com_android_internal_security_VerityUtils),
- REG_JNI(register_com_android_internal_util_ArrayUtils),
REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_camera2_CameraMetadata),
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index a09c405..7ff1f8c 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -40,6 +40,7 @@
jmethodID dispatchHotplug;
jmethodID dispatchHotplugConnectionError;
jmethodID dispatchModeChanged;
+ jmethodID dispatchModeRejected;
jmethodID dispatchFrameRateOverrides;
jmethodID dispatchHdcpLevelsChanged;
@@ -95,6 +96,7 @@
void dispatchHotplugConnectionError(nsecs_t timestamp, int errorCode) override;
void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
nsecs_t renderPeriod) override;
+ void dispatchModeRejected(PhysicalDisplayId displayId, int32_t modeId) override;
void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
std::vector<FrameRateOverride> overrides) override;
void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
@@ -271,6 +273,18 @@
mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
}
+void NativeDisplayEventReceiver::dispatchModeRejected(PhysicalDisplayId displayId, int32_t modeId) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
+ if (receiverObj.get()) {
+ ALOGV("receiver %p ~ Invoking Mode Rejected handler.", this);
+ env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchModeRejected,
+ displayId.value, modeId);
+ ALOGV("receiver %p ~ Returned from Mode Rejected handler.", this);
+ }
+}
+
void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -405,6 +419,9 @@
gDisplayEventReceiverClassInfo.dispatchModeChanged =
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged",
"(JJIJ)V");
+ gDisplayEventReceiverClassInfo.dispatchModeRejected =
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeRejected",
+ "(JI)V");
gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides =
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
"dispatchFrameRateOverrides",
diff --git a/core/jni/com_android_internal_util_ArrayUtils.cpp b/core/jni/com_android_internal_util_ArrayUtils.cpp
deleted file mode 100644
index c69e6c9..0000000
--- a/core/jni/com_android_internal_util_ArrayUtils.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ArrayUtils"
-
-#include <android-base/logging.h>
-#include <jni.h>
-#include <nativehelper/JNIHelp.h>
-#include <string.h>
-#include <unistd.h>
-#include <utils/Log.h>
-
-namespace android {
-
-static size_t GetCacheLineSize() {
- long size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
- if (size <= 0) {
- ALOGE("Unable to determine L1 data cache line size. Assuming 32 bytes");
- return 32;
- }
- return size;
-}
-
-#ifdef __aarch64__
-static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) {
- // Execute 'dc cvac' at least once on each cache line in the memory region.
- //
- // 'dc cvac' stands for "Data Cache line Clean by Virtual Address to point-of-Coherency".
- // It writes the cache line back to the "point-of-coherency", i.e. main memory.
- //
- // Since the memory region is not guaranteed to be cache-line-aligned, we use an "extra"
- // instruction after the loop to make sure the last cache line gets covered.
- for (size_t i = 0; i < size; i += cache_line_size) {
- asm volatile("dc cvac, %0" ::"r"(p + i));
- }
- asm volatile("dc cvac, %0" ::"r"(p + size - 1));
-}
-#elif defined(__i386__) || defined(__x86_64__)
-static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) {
- for (size_t i = 0; i < size; i += cache_line_size) {
- asm volatile("clflush (%0)" ::"r"(p + i));
- }
- asm volatile("clflush (%0)" ::"r"(p + size - 1));
-}
-#elif defined(__riscv)
-static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) {
- // This should eventually work, but it is not ready to be enabled yet:
- // 1.) The Android emulator needs to add support for zicbom.
- // 2.) Kernel needs to enable zicbom in usermode.
- // 3.) Android clang needs to add zicbom to the target.
-#if 0
- for (size_t i = 0; i < size; i += cache_line_size) {
- asm volatile("cbo.clean (%0)" ::"r"(p + i));
- }
- asm volatile("cbo.clean (%0)" ::"r"(p + size - 1));
-#endif
-}
-#elif defined(__arm__)
-// arm32 has a cacheflush() syscall, but it is undocumented and only flushes the icache.
-// It is not the same as cacheflush(2) as documented in the Linux man-pages project.
-static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) {}
-#else
-#error "Unknown architecture"
-#endif
-
-static void ZeroizePrimitiveArray(JNIEnv* env, jclass clazz, jarray array, size_t component_len) {
- static const size_t cache_line_size = GetCacheLineSize();
-
- size_t size = env->GetArrayLength(array) * component_len;
- if (size == 0) {
- return;
- }
-
- // ART guarantees that GetPrimitiveArrayCritical never copies.
- jboolean isCopy;
- void* elems = env->GetPrimitiveArrayCritical(array, &isCopy);
- CHECK(!isCopy);
-
-#ifdef __BIONIC__
- memset_explicit(elems, 0, size);
-#else
- memset(elems, 0, size);
-#endif
- // Clean the data cache so that the data gets zeroized in main memory right away. Without this,
- // it might not be written to main memory until the cache line happens to be evicted.
- CleanDataCache(static_cast<const uint8_t*>(elems), size, cache_line_size);
-
- env->ReleasePrimitiveArrayCritical(array, elems, /* mode= */ 0);
-}
-
-static void ZeroizeByteArray(JNIEnv* env, jclass clazz, jbyteArray array) {
- ZeroizePrimitiveArray(env, clazz, array, sizeof(jbyte));
-}
-
-static void ZeroizeCharArray(JNIEnv* env, jclass clazz, jcharArray array) {
- ZeroizePrimitiveArray(env, clazz, array, sizeof(jchar));
-}
-
-static const JNINativeMethod sMethods[] = {
- {"zeroize", "([B)V", (void*)ZeroizeByteArray},
- {"zeroize", "([C)V", (void*)ZeroizeCharArray},
-};
-
-int register_com_android_internal_util_ArrayUtils(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/internal/util/ArrayUtils", sMethods,
- NELEM(sMethods));
-}
-
-} // namespace android
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8c46ccc..238aca5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -10570,6 +10570,32 @@
<declare-styleable name="DateTimeView">
<attr name="showRelative" format="boolean" />
+ <!-- For relative times, controls what kinds of times get disambiguation text.
+
+ The default value is "future".
+
+ Does nothing if showRelative=false.
+ -->
+ <attr name="relativeTimeDisambiguationText">
+ <!-- Times in the past will have extra clarifying text indicating that the time is in
+ the past. For example, 1 minute ago is represented as "1m ago". If this flag is not
+ set, times in the past are represented as just "1m". -->
+ <flag name="past" value="0x01" />
+ <!-- Times in the future will have extra clarifying text indicating that the time is in
+ the future. For example, 1 minute in the future is represented as "in 1m". If this
+ flag is not set, times in the future are represented as just "1m". -->
+ <flag name="future" value="0x02" />
+ </attr>
+ <!-- For relative times, sets the length of the time unit displayed (minutes, hours, etc.).
+
+ Does nothing if showRelative=false.
+ -->
+ <attr name="relativeTimeUnitDisplayLength">
+ <!-- The time unit will be shown as a short as possible (1 character if possible). -->
+ <enum name="shortest" value="0" />
+ <!-- The time unit will be shortened to a medium length (2-3 characters in general). -->
+ <enum name="medium" value="1" />
+ </attr>
</declare-styleable>
<declare-styleable name="ResolverDrawerLayout_LayoutParams">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a2b7de1..390fbea 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -815,6 +815,11 @@
we rely on gravity to determine the effective orientation. -->
<bool name="config_deskDockEnablesAccelerometer">true</bool>
+ <!-- Control for allowing the dock rotation functionality before provision like
+ when the SetupWizard is being shown to the user. This defaults to false to
+ preserve existing behavior. -->
+ <bool name="config_allowDockBeforeProvision">false</bool>
+
<!-- Car dock behavior -->
<!-- The number of degrees to rotate the display when the device is in a car dock.
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d498b91..cfc3ddc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3135,6 +3135,86 @@
in <xliff:g id="count">%d</xliff:g>y
</string>
+ <!-- Phrase describing a time duration using minutes that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+ <string name="duration_minutes_shortest_past">
+ <xliff:g id="count">%d</xliff:g>m ago
+ </string>
+
+ <!-- Phrase describing a time duration using hours that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+ <string name="duration_hours_shortest_past">
+ <xliff:g id="count">%d</xliff:g>h ago
+ </string>
+
+ <!-- Phrase describing a time duration using days that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+ <string name="duration_days_shortest_past">
+ <xliff:g example="1" id="count">%d</xliff:g>d ago
+ </string>
+
+ <!-- Phrase describing a time duration using years that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+ <string name="duration_years_shortest_past">
+ <xliff:g id="count">%d</xliff:g>y ago
+ </string>
+
+ <!-- Phrase describing a time duration using minutes that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
+ <string name="duration_minutes_medium">
+ <xliff:g id="count">%d</xliff:g>min
+ </string>
+
+ <!-- Phrase describing a time duration using hours that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
+ <string name="duration_hours_medium">
+ <xliff:g id="count">%d</xliff:g>hr
+ </string>
+
+ <!-- Phrase describing a time duration using days that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
+ <string name="duration_days_medium">
+ <xliff:g id="count">%d</xliff:g>d
+ </string>
+
+ <!-- Phrase describing a time duration using years that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
+ <string name="duration_years_medium">
+ <xliff:g id="count">%d</xliff:g>yr
+ </string>
+
+ <!-- Phrase describing a time duration using minutes that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+ <string name="duration_minutes_medium_future">
+ in <xliff:g id="count">%d</xliff:g>min
+ </string>
+
+ <!-- Phrase describing a time duration using hours that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+ <string name="duration_hours_medium_future">
+ in <xliff:g id="count">%d</xliff:g>hr
+ </string>
+
+ <!-- Phrase describing a time duration using days that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+ <string name="duration_days_medium_future">
+ in <xliff:g example="1" id="count">%d</xliff:g>d
+ </string>
+
+ <!-- Phrase describing a time duration using years that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+ <string name="duration_years_medium_future">
+ in <xliff:g id="count">%d</xliff:g>yr
+ </string>
+
+ <!-- Phrase describing a time duration using minutes that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+ <string name="duration_minutes_medium_past">
+ <xliff:g id="count">%d</xliff:g>min ago
+ </string>
+
+ <!-- Phrase describing a time duration using hours that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+ <string name="duration_hours_medium_past">
+ <xliff:g id="count">%d</xliff:g>hr ago
+ </string>
+
+ <!-- Phrase describing a time duration using days that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+ <string name="duration_days_medium_past">
+ <xliff:g example="1" id="count">%d</xliff:g>d ago
+ </string>
+
+ <!-- Phrase describing a time duration using years that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+ <string name="duration_years_medium_past">
+ <xliff:g id="count">%d</xliff:g>yr ago
+ </string>
+
<!-- Phrase describing a relative time using minutes in the past that is not shown on the screen but used for accessibility. [CHAR LIMIT=NONE] -->
<string name="duration_minutes_relative">{count, plural,
=1 {# minute ago}
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9a51b72..2671ff9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1797,6 +1797,7 @@
<java-symbol type="bool" name="config_customUserSwitchUi" />
<java-symbol type="bool" name="config_canRemoveFirstAccount" />
<java-symbol type="string" name="config_accountTypeToKeepFirstAccount" />
+ <java-symbol type="bool" name="config_allowDockBeforeProvision" />
<java-symbol type="bool" name="config_deskDockEnablesAccelerometer" />
<java-symbol type="bool" name="config_disableMenuKeyInLockScreen" />
<java-symbol type="bool" name="config_enableCarDockHomeLaunch" />
@@ -3367,6 +3368,23 @@
<java-symbol type="string" name="duration_hours_shortest_future" />
<java-symbol type="string" name="duration_days_shortest_future" />
<java-symbol type="string" name="duration_years_shortest_future" />
+ <java-symbol type="string" name="duration_minutes_shortest_past" />
+ <java-symbol type="string" name="duration_hours_shortest_past" />
+ <java-symbol type="string" name="duration_days_shortest_past" />
+ <java-symbol type="string" name="duration_years_shortest_past" />
+
+ <java-symbol type="string" name="duration_minutes_medium" />
+ <java-symbol type="string" name="duration_hours_medium" />
+ <java-symbol type="string" name="duration_days_medium" />
+ <java-symbol type="string" name="duration_years_medium" />
+ <java-symbol type="string" name="duration_minutes_medium_future" />
+ <java-symbol type="string" name="duration_hours_medium_future" />
+ <java-symbol type="string" name="duration_days_medium_future" />
+ <java-symbol type="string" name="duration_years_medium_future" />
+ <java-symbol type="string" name="duration_minutes_medium_past" />
+ <java-symbol type="string" name="duration_hours_medium_past" />
+ <java-symbol type="string" name="duration_days_medium_past" />
+ <java-symbol type="string" name="duration_years_medium_past" />
<java-symbol type="string" name="duration_minutes_relative" />
<java-symbol type="string" name="duration_hours_relative" />
diff --git a/core/tests/coretests/src/android/widget/DateTimeViewTest.java b/core/tests/coretests/src/android/widget/DateTimeViewTest.java
index a8fd913..be65277 100644
--- a/core/tests/coretests/src/android/widget/DateTimeViewTest.java
+++ b/core/tests/coretests/src/android/widget/DateTimeViewTest.java
@@ -69,6 +69,141 @@
Assert.assertFalse(dateTimeView.wasLayoutRequested());
}
+ @UiThreadTest
+ @Test
+ public void disambiguationTextMask_none_noPastOrFutureDisambiguationText() {
+ final TestDateTimeView dateTimeView = new TestDateTimeView();
+ dateTimeView.setShowRelativeTime(true);
+ dateTimeView.setRelativeTimeDisambiguationTextMask(0);
+
+ // Minutes
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofMinutes(8).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("in"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofMinutes(8).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("ago"));
+
+ // Hours
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofHours(4).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("in"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofHours(4).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("ago"));
+
+ // Days
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(14).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("in"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(14).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("ago"));
+
+ // Years
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(400).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("in"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(400).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("ago"));
+ }
+
+ @UiThreadTest
+ @Test
+ public void disambiguationTextMask_bothPastAndFuture_usesPastAndFutureDisambiguationText() {
+ final TestDateTimeView dateTimeView = new TestDateTimeView();
+ dateTimeView.setShowRelativeTime(true);
+ dateTimeView.setRelativeTimeDisambiguationTextMask(
+ DateTimeView.DISAMBIGUATION_TEXT_PAST | DateTimeView.DISAMBIGUATION_TEXT_FUTURE);
+
+ // Minutes
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofMinutes(8).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("in"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofMinutes(8).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("ago"));
+
+ // Hours
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofHours(4).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("in"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofHours(4).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("ago"));
+
+ // Days
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(14).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("in"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(14).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("ago"));
+
+ // Years
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(400).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("in"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(400).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("ago"));
+ }
+
+ @UiThreadTest
+ @Test
+ public void unitDisplayLength_shortest_noMediumText() {
+ final TestDateTimeView dateTimeView = new TestDateTimeView();
+ dateTimeView.setShowRelativeTime(true);
+ dateTimeView.setRelativeTimeUnitDisplayLength(DateTimeView.UNIT_DISPLAY_LENGTH_SHORTEST);
+
+ // Minutes
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofMinutes(8).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("min"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofMinutes(8).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("min"));
+
+ // Hours
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofHours(4).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("hr"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofHours(4).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("hr"));
+
+ // Days excluded because the string is the same for both shortest length and medium length
+
+ // Years
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(400).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("yr"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(400).toMillis());
+ Assert.assertFalse(dateTimeView.getText().toString().contains("yr"));
+ }
+
+ @UiThreadTest
+ @Test
+ public void unitDisplayLength_medium_usesMediumText() {
+ final TestDateTimeView dateTimeView = new TestDateTimeView();
+ dateTimeView.setShowRelativeTime(true);
+ dateTimeView.setRelativeTimeUnitDisplayLength(DateTimeView.UNIT_DISPLAY_LENGTH_MEDIUM);
+
+ // Minutes
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofMinutes(8).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("min"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofMinutes(8).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("min"));
+
+ // Hours
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofHours(4).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("hr"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofHours(4).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("hr"));
+
+ // Days excluded because the string is the same for both shortest length and medium length
+
+ // Years
+ dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(400).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("yr"));
+
+ dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(400).toMillis());
+ Assert.assertTrue(dateTimeView.getText().toString().contains("yr"));
+ }
+
private static class TestDateTimeView extends DateTimeView {
private boolean mRequestedLayout = false;
diff --git a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
index 3c264f1..3b9f35b 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -496,51 +496,4 @@
// expected
}
}
-
- // Note: the zeroize() tests only test the behavior that can be tested from a Java test.
- // They do not verify that no copy of the data is left anywhere.
-
- @Test
- @SmallTest
- public void testZeroizeNonMovableByteArray() {
- final int length = 10;
- byte[] array = ArrayUtils.newNonMovableByteArray(length);
- assertArrayEquals(array, new byte[length]);
- Arrays.fill(array, (byte) 0xff);
- ArrayUtils.zeroize(array);
- assertArrayEquals(array, new byte[length]);
- }
-
- @Test
- @SmallTest
- public void testZeroizeRegularByteArray() {
- final int length = 10;
- byte[] array = new byte[length];
- assertArrayEquals(array, new byte[length]);
- Arrays.fill(array, (byte) 0xff);
- ArrayUtils.zeroize(array);
- assertArrayEquals(array, new byte[length]);
- }
-
- @Test
- @SmallTest
- public void testZeroizeNonMovableCharArray() {
- final int length = 10;
- char[] array = ArrayUtils.newNonMovableCharArray(length);
- assertArrayEquals(array, new char[length]);
- Arrays.fill(array, (char) 0xff);
- ArrayUtils.zeroize(array);
- assertArrayEquals(array, new char[length]);
- }
-
- @Test
- @SmallTest
- public void testZeroizeRegularCharArray() {
- final int length = 10;
- char[] array = new char[length];
- assertArrayEquals(array, new char[length]);
- Arrays.fill(array, (char) 0xff);
- ArrayUtils.zeroize(array);
- assertArrayEquals(array, new char[length]);
- }
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 897fc54..a26f5e3 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -514,7 +514,6 @@
<permission name="android.permission.RENOUNCE_PERMISSIONS" />
<permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" />
<permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" />
- <permission name="android.permission.READ_DROPBOX_DATA" />
<permission name="android.permission.READ_LOGS" />
<permission name="android.permission.BRIGHTNESS_SLIDER_USAGE" />
<permission name="android.permission.ACCESS_AMBIENT_LIGHT_STATS" />
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 073307c..d010c52 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -301,10 +301,7 @@
*
* @param bounds Returns the computed bounds of the path's control points.
* @param exact This parameter is no longer used.
- *
- * @deprecated use computeBounds(RectF) instead
*/
- @Deprecated
@SuppressWarnings({"UnusedDeclaration"})
public void computeBounds(@NonNull RectF bounds, boolean exact) {
computeBounds(bounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 032dac9..37d5878 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -1317,9 +1317,6 @@
// otherwise a new transition will notify the relevant observers
if (returningToApp && allAppsAreTranslucent(mPausingTasks)) {
mHomeTransitionObserver.notifyHomeVisibilityChanged(true);
- } else if (!toHome && mState == STATE_NEW_TASK
- && allAppsAreTranslucent(mOpeningTasks)) {
- // We are opening a translucent app. Launcher is still visible so we do nothing.
} else if (!toHome) {
// For some transitions, we may have notified home activity that it became
// visible. We need to notify the observer that we are no longer going home.
diff --git a/native/android/display_luts.cpp b/native/android/display_luts.cpp
index 179a32b..b03a718 100644
--- a/native/android/display_luts.cpp
+++ b/native/android/display_luts.cpp
@@ -26,8 +26,9 @@
#define CHECK_NOT_NULL(name) \
LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
-ADisplayLutsEntry* ADisplayLutsEntry_createEntry(float* buffer, int32_t length, int32_t dimension,
- int32_t key) {
+ADisplayLutsEntry* ADisplayLutsEntry_createEntry(float* buffer, int32_t length,
+ ADisplayLuts_Dimension dimension,
+ ADisplayLuts_SamplingKey key) {
CHECK_NOT_NULL(buffer);
LOG_ALWAYS_FATAL_IF(length >= ADISPLAYLUTS_BUFFER_LENGTH_LIMIT,
"the lut raw buffer length is too big to handle");
@@ -64,7 +65,7 @@
ADisplayLuts_Dimension ADisplayLutsEntry_getDimension(const ADisplayLutsEntry* entry) {
CHECK_NOT_NULL(entry);
- return static_cast<ADisplayLuts_Dimension>(entry->properties.dimension);
+ return entry->properties.dimension;
}
int32_t ADisplayLutsEntry_getSize(const ADisplayLutsEntry* entry) {
@@ -74,7 +75,7 @@
ADisplayLuts_SamplingKey ADisplayLutsEntry_getSamplingKey(const ADisplayLutsEntry* entry) {
CHECK_NOT_NULL(entry);
- return static_cast<ADisplayLuts_SamplingKey>(entry->properties.samplingKey);
+ return entry->properties.samplingKey;
}
const float* ADisplayLutsEntry_getBuffer(const ADisplayLutsEntry* _Nonnull entry) {
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 6bca145..4fe0b80 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -64,6 +64,8 @@
static_cast<int>(android::gui::LutProperties::SamplingKey::RGB));
static_assert(static_cast<int>(ADISPLAYLUTS_SAMPLINGKEY_MAX_RGB) ==
static_cast<int>(android::gui::LutProperties::SamplingKey::MAX_RGB));
+static_assert(static_cast<int>(ADISPLAYLUTS_SAMPLINGKEY_CIE_Y) ==
+ static_cast<int>(android::gui::LutProperties::SamplingKey::CIE_Y));
Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) {
return reinterpret_cast<Transaction*>(aSurfaceTransaction);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0ec5571..fa6e2db 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -65,7 +65,6 @@
<uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
<uses-permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" />
<uses-permission android:name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" />
- <uses-permission android:name="android.permission.READ_DROPBOX_DATA" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.BRIGHTNESS_SLIDER_USAGE" />
<uses-permission android:name="android.permission.ACCESS_AMBIENT_LIGHT_STATS" />
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index e2f28fa..e445884 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -427,6 +427,18 @@
}
}
+
+flag {
+ name: "status_bar_chips_modernization"
+ namespace: "systemui"
+ description: "Deprecate OngoingCallController and implement OngoingActivityChips"
+ "in compose"
+ bug: "372657935"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
flag {
name: "status_bar_use_repos_for_call_chip"
namespace: "systemui"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
index c287da8..407bdf8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
@@ -662,7 +662,7 @@
val standardAddShortcutRequest =
ShortcutCustomizationRequestInfo.Add(
label = "Standard shortcut",
- categoryType = ShortcutCategoryType.System,
+ categoryType = System,
subCategoryLabel = "Standard subcategory",
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
index 2d05ee0..755c218 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
@@ -108,7 +108,7 @@
viewModel.onShortcutCustomizationRequested(ShortcutCustomizationRequestInfo.Reset)
val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
- assertThat(uiState).isEqualTo(ResetShortcutDialog())
+ assertThat(uiState).isEqualTo(ResetShortcutDialog)
}
}
@@ -118,45 +118,7 @@
viewModel.onShortcutCustomizationRequested(allAppsShortcutDeleteRequest)
val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
- assertThat(uiState).isEqualTo(DeleteShortcutDialog())
- }
- }
-
- @Test
- fun uiState_consumedOnAddDialogShown() {
- testScope.runTest {
- val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
- viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
- viewModel.onDialogShown()
-
- assertThat((uiState as AddShortcutDialog).isDialogShowing)
- .isTrue()
- }
- }
-
- @Test
- fun uiState_consumedOnDeleteDialogShown() {
- testScope.runTest {
- val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
- viewModel.onShortcutCustomizationRequested(allAppsShortcutDeleteRequest)
- viewModel.onDialogShown()
-
- assertThat(
- (uiState as DeleteShortcutDialog).isDialogShowing
- )
- .isTrue()
- }
- }
-
- @Test
- fun uiState_consumedOnResetDialogShown() {
- testScope.runTest {
- val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
- viewModel.onShortcutCustomizationRequested(ShortcutCustomizationRequestInfo.Reset)
- viewModel.onDialogShown()
-
- assertThat((uiState as ResetShortcutDialog).isDialogShowing)
- .isTrue()
+ assertThat(uiState).isEqualTo(DeleteShortcutDialog)
}
}
@@ -165,7 +127,6 @@
testScope.runTest {
val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
- viewModel.onDialogShown()
viewModel.onDialogDismissed()
assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
}
@@ -199,7 +160,6 @@
testScope.runTest {
val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
viewModel.onShortcutCustomizationRequested(allAppsShortcutAddRequest)
- viewModel.onDialogShown()
assertThat((uiState as AddShortcutDialog).errorMessage)
.isEmpty()
@@ -339,7 +299,6 @@
private suspend fun openAddShortcutDialogAndSetShortcut() {
viewModel.onShortcutCustomizationRequested(allAppsShortcutAddRequest)
- viewModel.onDialogShown()
viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
viewModel.onKeyPressed(keyUpEventWithActionKeyPressed)
@@ -349,14 +308,12 @@
private suspend fun openDeleteShortcutDialogAndDeleteShortcut() {
viewModel.onShortcutCustomizationRequested(allAppsShortcutDeleteRequest)
- viewModel.onDialogShown()
viewModel.deleteShortcutCurrentlyBeingCustomized()
}
private suspend fun openResetShortcutDialogAndResetAllCustomShortcuts() {
viewModel.onShortcutCustomizationRequested(ShortcutCustomizationRequestInfo.Reset)
- viewModel.onDialogShown()
viewModel.resetAllCustomShortcuts()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
similarity index 83%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
index 3bd2496..78fce27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
@@ -18,6 +18,13 @@
import android.app.role.RoleManager
import android.app.role.mockRoleManager
+import android.content.Context
+import android.content.Context.INPUT_SERVICE
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.NameNotFoundException
+import android.hardware.input.InputGestureData
+import android.hardware.input.fakeInputManager
import android.view.KeyEvent
import android.view.KeyboardShortcutGroup
import android.view.KeyboardShortcutInfo
@@ -31,6 +38,7 @@
import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allAppsInputGestureData
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.CurrentApp
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
@@ -56,7 +64,6 @@
import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.settings.userTracker
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SHORTCUT_HELPER_SHOWING
-import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.UnconfinedTestDispatcher
@@ -64,6 +71,10 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -73,6 +84,9 @@
private val fakeSystemSource = FakeKeyboardShortcutGroupsSource()
private val fakeMultiTaskingSource = FakeKeyboardShortcutGroupsSource()
private val fakeCurrentAppsSource = FakeKeyboardShortcutGroupsSource()
+ private val mockPackageManager: PackageManager = mock()
+ private val mockUserContext: Context = mock()
+ private val mockApplicationInfo: ApplicationInfo = mock()
private val kosmos =
Kosmos().also {
@@ -83,7 +97,7 @@
it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
it.shortcutHelperInputShortcutsSource = FakeKeyboardShortcutGroupsSource()
it.shortcutHelperCurrentAppShortcutsSource = fakeCurrentAppsSource
- it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { context })
+ it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockUserContext })
}
private val testScope = kosmos.testScope
@@ -91,13 +105,20 @@
private val sysUiState = kosmos.sysUiState
private val fakeUserTracker = kosmos.fakeUserTracker
private val mockRoleManager = kosmos.mockRoleManager
+ private val inputManager = kosmos.fakeInputManager.inputManager
private val viewModel = kosmos.shortcutHelperViewModel
+
@Before
fun setUp() {
fakeSystemSource.setGroups(TestShortcuts.systemGroups)
fakeMultiTaskingSource.setGroups(TestShortcuts.multitaskingGroups)
fakeCurrentAppsSource.setGroups(TestShortcuts.currentAppGroups)
+ whenever(mockPackageManager.getApplicationInfo(anyString(), eq(0))).thenReturn(mockApplicationInfo)
+ whenever(mockPackageManager.getApplicationLabel(mockApplicationInfo)).thenReturn("Current App")
+ whenever(mockPackageManager.getApplicationIcon(anyString())).thenThrow(NameNotFoundException())
+ whenever(mockUserContext.packageManager).thenReturn(mockPackageManager)
+ whenever(mockUserContext.getSystemService(INPUT_SERVICE)).thenReturn(inputManager)
}
@Test
@@ -259,11 +280,11 @@
fun shortcutsUiState_currentAppIsLauncher_defaultSelectedCategoryIsSystem() =
testScope.runTest {
whenever(
- mockRoleManager.getRoleHoldersAsUser(
- RoleManager.ROLE_HOME,
- fakeUserTracker.userHandle,
- )
+ mockRoleManager.getRoleHoldersAsUser(
+ RoleManager.ROLE_HOME,
+ fakeUserTracker.userHandle,
)
+ )
.thenReturn(listOf(TestShortcuts.currentAppPackageName))
val uiState by collectLastValue(viewModel.shortcutsUiState)
@@ -299,23 +320,23 @@
label = "System",
iconSource = IconSource(imageVector = Icons.Default.Tv),
shortcutCategory =
- ShortcutCategory(
- System,
- subCategoryWithShortcutLabels("first Foo shortcut1"),
- subCategoryWithShortcutLabels(
- "second foO shortcut2",
- subCategoryLabel = SECOND_SIMPLE_GROUP_LABEL,
- ),
+ ShortcutCategory(
+ System,
+ subCategoryWithShortcutLabels("first Foo shortcut1"),
+ subCategoryWithShortcutLabels(
+ "second foO shortcut2",
+ subCategoryLabel = SECOND_SIMPLE_GROUP_LABEL,
),
+ ),
),
ShortcutCategoryUi(
label = "Multitasking",
iconSource = IconSource(imageVector = Icons.Default.VerticalSplit),
shortcutCategory =
- ShortcutCategory(
- MultiTasking,
- subCategoryWithShortcutLabels("third FoO shortcut1"),
- ),
+ ShortcutCategory(
+ MultiTasking,
+ subCategoryWithShortcutLabels("third FoO shortcut1"),
+ ),
),
)
}
@@ -387,6 +408,31 @@
assertThat(activeUiState.defaultSelectedCategory).isInstanceOf(CurrentApp::class.java)
}
+ @Test
+ fun shortcutsUiState_shouldShowResetButton_isFalseWhenThereAreNoCustomShortcuts() =
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutsUiState)
+
+ testHelper.showFromActivity()
+
+ val activeUiState = uiState as ShortcutsUiState.Active
+ assertThat(activeUiState.shouldShowResetButton).isFalse()
+ }
+
+ @Test
+ fun shortcutsUiState_shouldShowResetButton_isTrueWhenThereAreCustomShortcuts() =
+ testScope.runTest {
+ whenever(
+ inputManager.getCustomInputGestures(/* filter= */ InputGestureData.Filter.KEY)
+ ).thenReturn(listOf(allAppsInputGestureData))
+ val uiState by collectLastValue(viewModel.shortcutsUiState)
+
+ testHelper.showFromActivity()
+
+ val activeUiState = uiState as ShortcutsUiState.Active
+ assertThat(activeUiState.shouldShowResetButton).isTrue()
+ }
+
private fun groupWithShortcutLabels(
vararg shortcutLabels: String,
groupLabel: String = FIRST_SIMPLE_GROUP_LABEL,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
index 9f84e34..f33de4d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
@@ -128,7 +128,7 @@
viewModel,
dialogManager,
wifiStateWorker,
- accessPointController
+ accessPointController,
)
underTest.initialize()
@@ -156,10 +156,7 @@
testScope.runTest {
connectivityRepository.defaultConnections.value = DefaultConnectionModel()
wifiRepository.wifiScanResults.value =
- listOf(
- WifiScanEntry(ssid = "ssid 1"),
- WifiScanEntry(ssid = "ssid 2"),
- )
+ listOf(WifiScanEntry(ssid = "ssid 1"), WifiScanEntry(ssid = "ssid 2"))
runCurrent()
looper.processAllMessages()
@@ -204,10 +201,7 @@
testScope.runTest {
airplaneModeRepository.setIsAirplaneMode(true)
connectivityRepository.defaultConnections.value =
- DefaultConnectionModel(
- wifi = Wifi(true),
- isValidated = true,
- )
+ DefaultConnectionModel(wifi = Wifi(true), isValidated = true)
wifiRepository.setIsWifiEnabled(true)
wifiRepository.setWifiNetwork(ACTIVE_WIFI)
@@ -222,10 +216,7 @@
fun wifiConnected() =
testScope.runTest {
connectivityRepository.defaultConnections.value =
- DefaultConnectionModel(
- wifi = Wifi(true),
- isValidated = true,
- )
+ DefaultConnectionModel(wifi = Wifi(true), isValidated = true)
wifiRepository.setIsWifiEnabled(true)
wifiRepository.setWifiNetwork(ACTIVE_WIFI)
@@ -242,6 +233,7 @@
whenever(wifiStateWorker.isWifiEnabled).thenReturn(true)
underTest.secondaryClick(null)
+ looper.processAllMessages()
verify(wifiStateWorker, times(1)).isWifiEnabled = eq(false)
}
@@ -251,6 +243,7 @@
whenever(wifiStateWorker.isWifiEnabled).thenReturn(false)
underTest.secondaryClick(null)
+ looper.processAllMessages()
verify(wifiStateWorker, times(1)).isWifiEnabled = eq(true)
}
@@ -258,10 +251,6 @@
companion object {
const val WIFI_SSID = "test ssid"
val ACTIVE_WIFI =
- WifiNetworkModel.Active.of(
- isValidated = true,
- level = 4,
- ssid = WIFI_SSID,
- )
+ WifiNetworkModel.Active.of(isValidated = true, level = 4, ssid = WIFI_SSID)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java
index 0cf9604..b5ec0a0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java
@@ -180,6 +180,7 @@
when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
mTile.secondaryClick(null);
+ mTestableLooper.processAllMessages();
verify(mWifiStateWorker, times(1)).setWifiEnabled(eq(false));
}
@@ -189,6 +190,7 @@
when(mWifiStateWorker.isWifiEnabled()).thenReturn(false);
mTile.secondaryClick(null);
+ mTestableLooper.processAllMessages();
verify(mWifiStateWorker, times(1)).setWifiEnabled(eq(true));
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
index 7fed47a..e96dd16 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
@@ -42,7 +42,8 @@
fun notificationChip_startsWithStartingModel() =
kosmos.runTest {
val icon = mock<StatusBarIconView>()
- val startingNotif = activeNotificationModel(key = "notif1", statusBarChipIcon = icon)
+ val startingNotif =
+ activeNotificationModel(key = "notif1", statusBarChipIcon = icon, whenTime = 5432)
val underTest = factory.create(startingNotif)
@@ -50,6 +51,7 @@
assertThat(latest!!.key).isEqualTo("notif1")
assertThat(latest!!.statusBarChipIconView).isEqualTo(icon)
+ assertThat(latest!!.whenTime).isEqualTo(5432)
}
@Test
@@ -65,11 +67,16 @@
val newIconView = mock<StatusBarIconView>()
underTest.setNotification(
- activeNotificationModel(key = "notif1", statusBarChipIcon = newIconView)
+ activeNotificationModel(
+ key = "notif1",
+ statusBarChipIcon = newIconView,
+ whenTime = 6543,
+ )
)
assertThat(latest!!.key).isEqualTo("notif1")
assertThat(latest!!.statusBarChipIconView).isEqualTo(newIconView)
+ assertThat(latest!!.whenTime).isEqualTo(6543)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
index 16376c5..a09cb69 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
@@ -101,7 +101,7 @@
assertThat(latest).hasSize(1)
val chip = latest!![0]
- assertThat(chip).isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
+ assertThat(chip).isInstanceOf(OngoingActivityChipModel.Shown.ShortTimeDelta::class.java)
assertThat(chip.icon).isEqualTo(OngoingActivityChipModel.ChipIcon.StatusBarView(icon))
}
@@ -171,7 +171,8 @@
companion object {
fun assertIsNotifChip(latest: OngoingActivityChipModel?, expectedIcon: StatusBarIconView) {
- assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
+ assertThat(latest)
+ .isInstanceOf(OngoingActivityChipModel.Shown.ShortTimeDelta::class.java)
assertThat((latest as OngoingActivityChipModel.Shown).icon)
.isEqualTo(OngoingActivityChipModel.ChipIcon.StatusBarView(expectedIcon))
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
deleted file mode 100644
index 3bd12e6..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright (C) 2018 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 static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.platform.test.annotations.DisableFlags;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.View;
-import android.widget.TextView;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.ShadeHeadsUpTracker;
-import com.android.systemui.shade.ShadeViewController;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.HeadsUpStatusBarView;
-import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor;
-import com.android.systemui.statusbar.notification.headsup.PinnedStatus;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
-import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.policy.Clock;
-import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Optional;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@RunWithLooper
-public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
-
- private final NotificationStackScrollLayoutController mStackScrollerController =
- mock(NotificationStackScrollLayoutController.class);
- private final ShadeViewController mShadeViewController =
- mock(ShadeViewController.class);
- private final ShadeHeadsUpTracker mShadeHeadsUpTracker = mock(ShadeHeadsUpTracker.class);
- private final DarkIconDispatcher mDarkIconDispatcher = mock(DarkIconDispatcher.class);
- private HeadsUpAppearanceController mHeadsUpAppearanceController;
- private NotificationTestHelper mTestHelper;
- private ExpandableNotificationRow mRow;
- private NotificationEntry mEntry;
- private HeadsUpStatusBarView mHeadsUpStatusBarView;
- private HeadsUpManager mHeadsUpManager;
- private View mOperatorNameView;
- private StatusBarStateController mStatusbarStateController;
- private PhoneStatusBarTransitions mPhoneStatusBarTransitions;
- private KeyguardBypassController mBypassController;
- private NotificationWakeUpCoordinator mWakeUpCoordinator;
- private KeyguardStateController mKeyguardStateController;
- private CommandQueue mCommandQueue;
- private NotificationRoundnessManager mNotificationRoundnessManager;
-
- @Before
- public void setUp() throws Exception {
- allowTestableLooperAsMainThread();
- mTestHelper = new NotificationTestHelper(
- mContext,
- mDependency,
- TestableLooper.get(this));
- mRow = mTestHelper.createRow();
- mEntry = mRow.getEntry();
- mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
- mock(TextView.class));
- mHeadsUpManager = mock(HeadsUpManager.class);
- mOperatorNameView = new View(mContext);
- mStatusbarStateController = mock(StatusBarStateController.class);
- mPhoneStatusBarTransitions = mock(PhoneStatusBarTransitions.class);
- mBypassController = mock(KeyguardBypassController.class);
- mWakeUpCoordinator = mock(NotificationWakeUpCoordinator.class);
- mKeyguardStateController = mock(KeyguardStateController.class);
- mCommandQueue = mock(CommandQueue.class);
- mNotificationRoundnessManager = mock(NotificationRoundnessManager.class);
- when(mShadeViewController.getShadeHeadsUpTracker()).thenReturn(mShadeHeadsUpTracker);
- mHeadsUpAppearanceController = new HeadsUpAppearanceController(
- mHeadsUpManager,
- mStatusbarStateController,
- mPhoneStatusBarTransitions,
- mBypassController,
- mWakeUpCoordinator,
- mDarkIconDispatcher,
- mKeyguardStateController,
- mCommandQueue,
- mStackScrollerController,
- mShadeViewController,
- mNotificationRoundnessManager,
- mHeadsUpStatusBarView,
- new Clock(mContext, null),
- mock(HeadsUpNotificationIconInteractor.class),
- Optional.of(mOperatorNameView));
- mHeadsUpAppearanceController.setAppearFraction(0.0f, 0.0f);
- }
-
- @Test
- public void testShowinEntryUpdated() {
- mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
- when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
- when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
- mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
- assertEquals(mRow.getEntry(), mHeadsUpStatusBarView.getShowingEntry());
-
- mRow.setPinnedStatus(PinnedStatus.NotPinned);
- when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
- assertNull(mHeadsUpStatusBarView.getShowingEntry());
- }
-
- @Test
- public void testPinnedStatusUpdated() {
- mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
- when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
- when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
- mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
- assertEquals(PinnedStatus.PinnedBySystem, mHeadsUpAppearanceController.getPinnedStatus());
-
- mRow.setPinnedStatus(PinnedStatus.NotPinned);
- when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
- assertEquals(PinnedStatus.NotPinned, mHeadsUpAppearanceController.getPinnedStatus());
- }
-
- @Test
- @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
- public void testHeaderUpdated() {
- mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
- when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
- when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
- mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
- assertEquals(mRow.getHeaderVisibleAmount(), 0.0f, 0.0f);
-
- mRow.setPinnedStatus(PinnedStatus.NotPinned);
- when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
- assertEquals(mRow.getHeaderVisibleAmount(), 1.0f, 0.0f);
- }
-
- @Test
- public void testOperatorNameViewUpdated() {
- mHeadsUpAppearanceController.setAnimationsEnabled(false);
-
- mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
- when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
- when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
- mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
- assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility());
-
- mRow.setPinnedStatus(PinnedStatus.NotPinned);
- when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
- assertEquals(View.VISIBLE, mOperatorNameView.getVisibility());
- }
-
- @Test
- public void constructor_animationValuesUpdated() {
- float appearFraction = .75f;
- float expandedHeight = 400f;
- when(mStackScrollerController.getAppearFraction()).thenReturn(appearFraction);
- when(mStackScrollerController.getExpandedHeight()).thenReturn(expandedHeight);
-
- HeadsUpAppearanceController newController = new HeadsUpAppearanceController(
- mHeadsUpManager,
- mStatusbarStateController,
- mPhoneStatusBarTransitions,
- mBypassController,
- mWakeUpCoordinator,
- mDarkIconDispatcher,
- mKeyguardStateController,
- mCommandQueue,
- mStackScrollerController,
- mShadeViewController,
- mNotificationRoundnessManager,
- mHeadsUpStatusBarView,
- new Clock(mContext, null),
- mock(HeadsUpNotificationIconInteractor.class),
- Optional.empty());
-
- assertEquals(expandedHeight, newController.mExpandedHeight, 0.0f);
- assertEquals(appearFraction, newController.mAppearFraction, 0.0f);
- }
-
- @Test
- public void testDestroy() {
- reset(mHeadsUpManager);
- reset(mDarkIconDispatcher);
- reset(mShadeHeadsUpTracker);
- reset(mStackScrollerController);
-
- mHeadsUpAppearanceController.onViewDetached();
-
- verify(mHeadsUpManager).removeListener(any());
- verify(mDarkIconDispatcher).removeDarkReceiver(any());
- verify(mShadeHeadsUpTracker).removeTrackingHeadsUpListener(any());
- verify(mShadeHeadsUpTracker).setHeadsUpAppearanceController(isNull());
- verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any());
- }
-
- @Test
- public void testPulsingRoundness_onUpdateHeadsUpAndPulsingRoundness() {
- // Pulsing: Enable flag and dozing
- when(mNotificationRoundnessManager.shouldRoundNotificationPulsing()).thenReturn(true);
- when(mTestHelper.getStatusBarStateController().isDozing()).thenReturn(true);
-
- // Pulsing: Enabled
- mRow.setHeadsUp(true);
- mHeadsUpAppearanceController.updateHeadsUpAndPulsingRoundness(mEntry);
-
- String debugString = mRow.getRoundableState().debugString();
- assertEquals(
- "If Pulsing is enabled, roundness should be set to 1. Value: " + debugString,
- /* expected = */ 1,
- /* actual = */ mRow.getTopRoundness(),
- /* delta = */ 0.001
- );
- assertTrue(debugString.contains("Pulsing"));
-
- // Pulsing: Disabled
- mRow.setHeadsUp(false);
- mHeadsUpAppearanceController.updateHeadsUpAndPulsingRoundness(mEntry);
-
- assertEquals(
- "If Pulsing is disabled, roundness should be set to 0. Value: "
- + mRow.getRoundableState().debugString(),
- /* expected = */ 0,
- /* actual = */ mRow.getTopRoundness(),
- /* delta = */ 0.001
- );
- }
-
- @Test
- public void testPulsingRoundness_onHeadsUpStateChanged() {
- // Pulsing: Enable flag and dozing
- when(mNotificationRoundnessManager.shouldRoundNotificationPulsing()).thenReturn(true);
- when(mTestHelper.getStatusBarStateController().isDozing()).thenReturn(true);
-
- // Pulsing: Enabled
- mEntry.setHeadsUp(true);
- mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, true);
-
- String debugString = mRow.getRoundableState().debugString();
- assertEquals(
- "If Pulsing is enabled, roundness should be set to 1. Value: " + debugString,
- /* expected = */ 1,
- /* actual = */ mRow.getTopRoundness(),
- /* delta = */ 0.001
- );
- assertTrue(debugString.contains("Pulsing"));
-
- // Pulsing: Disabled
- mEntry.setHeadsUp(false);
- mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, false);
-
- assertEquals(
- "If Pulsing is disabled, roundness should be set to 0. Value: "
- + mRow.getRoundableState().debugString(),
- /* expected = */ 0,
- /* actual = */ mRow.getTopRoundness(),
- /* delta = */ 0.001
- );
- }
-
- @Test
- public void onHeadsUpStateChanged_true_transitionsNotified() {
- mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, true);
-
- verify(mPhoneStatusBarTransitions).onHeadsUpStateChanged(true);
- }
-
- @Test
- public void onHeadsUpStateChanged_false_transitionsNotified() {
- mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, false);
-
- verify(mPhoneStatusBarTransitions).onHeadsUpStateChanged(false);
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt
new file mode 100644
index 0000000..d017402
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2018 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.platform.test.annotations.DisableFlags
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import android.view.View
+import android.widget.TextView
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.shade.ShadeHeadsUpTracker
+import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.HeadsUpStatusBarView
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotificationTestHelper
+import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation
+import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.policy.Clock
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.reset
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+class HeadsUpAppearanceControllerTest : SysuiTestCase() {
+ private val mStackScrollerController: NotificationStackScrollLayoutController =
+ mock<NotificationStackScrollLayoutController>()
+ private val mShadeViewController: ShadeViewController = mock<ShadeViewController>()
+ private val mShadeHeadsUpTracker: ShadeHeadsUpTracker = mock<ShadeHeadsUpTracker>()
+ private val mDarkIconDispatcher: DarkIconDispatcher = mock<DarkIconDispatcher>()
+ private var mHeadsUpAppearanceController: HeadsUpAppearanceController? = null
+ private var mTestHelper: NotificationTestHelper? = null
+ private var mRow: ExpandableNotificationRow? = null
+ private var mEntry: NotificationEntry? = null
+ private var mHeadsUpStatusBarView: HeadsUpStatusBarView? = null
+ private var mHeadsUpManager: HeadsUpManager? = null
+ private var mOperatorNameView: View? = null
+ private var mStatusbarStateController: StatusBarStateController? = null
+ private var mPhoneStatusBarTransitions: PhoneStatusBarTransitions? = null
+ private var mBypassController: KeyguardBypassController? = null
+ private var mWakeUpCoordinator: NotificationWakeUpCoordinator? = null
+ private var mKeyguardStateController: KeyguardStateController? = null
+ private var mCommandQueue: CommandQueue? = null
+ private var mNotificationRoundnessManager: NotificationRoundnessManager? = null
+
+ @Before
+ @Throws(Exception::class)
+ fun setUp() {
+ allowTestableLooperAsMainThread()
+ mTestHelper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+ mRow = mTestHelper!!.createRow()
+ mEntry = mRow!!.entry
+ mHeadsUpStatusBarView = HeadsUpStatusBarView(mContext, mock<View>(), mock<TextView>())
+ mHeadsUpManager = mock<HeadsUpManager>()
+ mOperatorNameView = View(mContext)
+ mStatusbarStateController = mock<StatusBarStateController>()
+ mPhoneStatusBarTransitions = mock<PhoneStatusBarTransitions>()
+ mBypassController = mock<KeyguardBypassController>()
+ mWakeUpCoordinator = mock<NotificationWakeUpCoordinator>()
+ mKeyguardStateController = mock<KeyguardStateController>()
+ mCommandQueue = mock<CommandQueue>()
+ mNotificationRoundnessManager = mock<NotificationRoundnessManager>()
+ whenever(mShadeViewController.shadeHeadsUpTracker).thenReturn(mShadeHeadsUpTracker)
+ mHeadsUpAppearanceController =
+ HeadsUpAppearanceController(
+ mHeadsUpManager,
+ mStatusbarStateController,
+ mPhoneStatusBarTransitions,
+ mBypassController,
+ mWakeUpCoordinator,
+ mDarkIconDispatcher,
+ mKeyguardStateController,
+ mCommandQueue,
+ mStackScrollerController,
+ mShadeViewController,
+ mNotificationRoundnessManager,
+ mHeadsUpStatusBarView,
+ Clock(mContext, null),
+ mock<HeadsUpNotificationIconInteractor>(),
+ Optional.of(mOperatorNameView!!),
+ )
+ mHeadsUpAppearanceController!!.setAppearFraction(0.0f, 0.0f)
+ }
+
+ @Test
+ fun testShowinEntryUpdated() {
+ mRow!!.setPinnedStatus(PinnedStatus.PinnedBySystem)
+ whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(true)
+ whenever(mHeadsUpManager!!.getTopEntry()).thenReturn(mEntry)
+ mHeadsUpAppearanceController!!.onHeadsUpPinned(mEntry)
+ assertThat(mHeadsUpStatusBarView!!.showingEntry).isEqualTo(mRow!!.entry)
+
+ mRow!!.setPinnedStatus(PinnedStatus.NotPinned)
+ whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(false)
+ mHeadsUpAppearanceController!!.onHeadsUpUnPinned(mEntry)
+ assertThat(mHeadsUpStatusBarView!!.showingEntry).isNull()
+ }
+
+ @Test
+ fun testPinnedStatusUpdated() {
+ mRow!!.setPinnedStatus(PinnedStatus.PinnedBySystem)
+ whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(true)
+ whenever(mHeadsUpManager!!.getTopEntry()).thenReturn(mEntry)
+ mHeadsUpAppearanceController!!.onHeadsUpPinned(mEntry)
+ assertThat(mHeadsUpAppearanceController!!.pinnedStatus)
+ .isEqualTo(PinnedStatus.PinnedBySystem)
+
+ mRow!!.setPinnedStatus(PinnedStatus.NotPinned)
+ whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(false)
+ mHeadsUpAppearanceController!!.onHeadsUpUnPinned(mEntry)
+ assertThat(mHeadsUpAppearanceController!!.pinnedStatus).isEqualTo(PinnedStatus.NotPinned)
+ }
+
+ @Test
+ @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
+ fun testHeaderUpdated() {
+ mRow!!.setPinnedStatus(PinnedStatus.PinnedBySystem)
+ whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(true)
+ whenever(mHeadsUpManager!!.getTopEntry()).thenReturn(mEntry)
+ mHeadsUpAppearanceController!!.onHeadsUpPinned(mEntry)
+ assertThat(mRow!!.headerVisibleAmount).isEqualTo(0.0f)
+
+ mRow!!.setPinnedStatus(PinnedStatus.NotPinned)
+ whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(false)
+ mHeadsUpAppearanceController!!.onHeadsUpUnPinned(mEntry)
+ assertThat(mRow!!.headerVisibleAmount).isEqualTo(1.0f)
+ }
+
+ @Test
+ fun testOperatorNameViewUpdated() {
+ mHeadsUpAppearanceController!!.setAnimationsEnabled(false)
+
+ mRow!!.setPinnedStatus(PinnedStatus.PinnedBySystem)
+ whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(true)
+ whenever(mHeadsUpManager!!.getTopEntry()).thenReturn(mEntry)
+ mHeadsUpAppearanceController!!.onHeadsUpPinned(mEntry)
+ assertThat(mOperatorNameView!!.visibility).isEqualTo(View.INVISIBLE)
+
+ mRow!!.setPinnedStatus(PinnedStatus.NotPinned)
+ whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(false)
+ mHeadsUpAppearanceController!!.onHeadsUpUnPinned(mEntry)
+ assertThat(mOperatorNameView!!.visibility).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ fun constructor_animationValuesUpdated() {
+ val appearFraction = .75f
+ val expandedHeight = 400f
+ whenever(mStackScrollerController.appearFraction).thenReturn(appearFraction)
+ whenever(mStackScrollerController.expandedHeight).thenReturn(expandedHeight)
+
+ val newController =
+ HeadsUpAppearanceController(
+ mHeadsUpManager,
+ mStatusbarStateController,
+ mPhoneStatusBarTransitions,
+ mBypassController,
+ mWakeUpCoordinator,
+ mDarkIconDispatcher,
+ mKeyguardStateController,
+ mCommandQueue,
+ mStackScrollerController,
+ mShadeViewController,
+ mNotificationRoundnessManager,
+ mHeadsUpStatusBarView,
+ Clock(mContext, null),
+ mock<HeadsUpNotificationIconInteractor>(),
+ Optional.empty(),
+ )
+
+ assertThat(newController.mExpandedHeight).isEqualTo(expandedHeight)
+ assertThat(newController.mAppearFraction).isEqualTo(appearFraction)
+ }
+
+ @Test
+ fun testDestroy() {
+ reset(mHeadsUpManager)
+ reset(mDarkIconDispatcher)
+ reset(mShadeHeadsUpTracker)
+ reset(mStackScrollerController)
+
+ mHeadsUpAppearanceController!!.onViewDetached()
+
+ verify(mHeadsUpManager!!).removeListener(any())
+ verify(mDarkIconDispatcher).removeDarkReceiver(any())
+ verify(mShadeHeadsUpTracker).removeTrackingHeadsUpListener(any())
+ verify(mShadeHeadsUpTracker).setHeadsUpAppearanceController(null)
+ verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any())
+ }
+
+ @Test
+ fun testPulsingRoundness_onUpdateHeadsUpAndPulsingRoundness() {
+ // Pulsing: Enable flag and dozing
+ whenever(mNotificationRoundnessManager!!.shouldRoundNotificationPulsing()).thenReturn(true)
+ whenever(mTestHelper!!.statusBarStateController.isDozing).thenReturn(true)
+
+ // Pulsing: Enabled
+ mRow!!.isHeadsUp = true
+ mHeadsUpAppearanceController!!.updateHeadsUpAndPulsingRoundness(mEntry)
+
+ val debugString: String = mRow!!.roundableState.debugString()
+ // If Pulsing is enabled, roundness should be set to 1
+ assertThat(mRow!!.topRoundness.toDouble()).isWithin(0.001).of(1.0)
+ assertThat(debugString).contains("Pulsing")
+
+ // Pulsing: Disabled
+ mRow!!.isHeadsUp = false
+ mHeadsUpAppearanceController!!.updateHeadsUpAndPulsingRoundness(mEntry)
+
+ // If Pulsing is disabled, roundness should be set to 0
+ assertThat(mRow!!.topRoundness.toDouble()).isWithin(0.001).of(0.0)
+ }
+
+ @Test
+ fun testPulsingRoundness_onHeadsUpStateChanged() {
+ // Pulsing: Enable flag and dozing
+ whenever(mNotificationRoundnessManager!!.shouldRoundNotificationPulsing()).thenReturn(true)
+ whenever(mTestHelper!!.statusBarStateController.isDozing).thenReturn(true)
+
+ // Pulsing: Enabled
+ mEntry!!.setHeadsUp(true)
+ mHeadsUpAppearanceController!!.onHeadsUpStateChanged(mEntry!!, true)
+
+ val debugString: String = mRow!!.roundableState.debugString()
+ // If Pulsing is enabled, roundness should be set to 1
+ assertThat(mRow!!.topRoundness.toDouble()).isWithin(0.001).of(1.0)
+ assertThat(debugString).contains("Pulsing")
+
+ // Pulsing: Disabled
+ mEntry!!.setHeadsUp(false)
+ mHeadsUpAppearanceController!!.onHeadsUpStateChanged(mEntry!!, false)
+
+ // If Pulsing is disabled, roundness should be set to 0
+ assertThat(mRow!!.topRoundness.toDouble()).isWithin(0.001).of(0.0)
+ }
+
+ @Test
+ fun onHeadsUpStateChanged_true_transitionsNotified() {
+ mHeadsUpAppearanceController!!.onHeadsUpStateChanged(mEntry!!, true)
+
+ verify(mPhoneStatusBarTransitions!!).onHeadsUpStateChanged(true)
+ }
+
+ @Test
+ fun onHeadsUpStateChanged_false_transitionsNotified() {
+ mHeadsUpAppearanceController!!.onHeadsUpStateChanged(mEntry!!, false)
+
+ verify(mPhoneStatusBarTransitions!!).onHeadsUpStateChanged(false)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
index 110dec6..f76ee5e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
@@ -87,7 +87,7 @@
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@OptIn(ExperimentalCoroutinesApi::class)
-@DisableFlags(FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP)
+@DisableFlags(FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP, StatusBarChipsModernization.FLAG_NAME)
class OngoingCallControllerViaListenerTest : SysuiTestCase() {
private val kosmos = Kosmos()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
index 2ad50cc..647b5f8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
@@ -29,6 +29,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON
+import com.android.systemui.Flags.FLAG_STATUS_BAR_CHIPS_MODERNIZATION
import com.android.systemui.Flags.FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS
import com.android.systemui.Flags.FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP
import com.android.systemui.SysuiTestCase
@@ -77,6 +78,7 @@
@TestableLooper.RunWithLooper
@OptIn(ExperimentalCoroutinesApi::class)
@EnableFlags(FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP)
+@DisableFlags(StatusBarChipsModernization.FLAG_NAME)
class OngoingCallControllerViaRepoTest : SysuiTestCase() {
private val kosmos = Kosmos()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
index 4c6eaa5..a446313 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
@@ -16,10 +16,13 @@
package com.android.systemui.statusbar.phone.ongoingcall.data.repository
+import android.platform.test.annotations.DisableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_STATUS_BAR_CHIPS_MODERNIZATION
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel
import com.google.common.truth.Truth.assertThat
@@ -28,6 +31,7 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
+@DisableFlags(StatusBarChipsModernization.FLAG_NAME)
class OngoingCallRepositoryTest : SysuiTestCase() {
private val kosmos = Kosmos()
private val underTest = kosmos.ongoingCallRepository
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
new file mode 100644
index 0000000..ca1413e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.phone.ongoingcall.domain.interactor
+
+import android.app.PendingIntent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.data.repository.activityManagerRepository
+import com.android.systemui.activity.data.repository.fake
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
+import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.shared.CallType
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class OngoingCallInteractorTest : SysuiTestCase() {
+ private val kosmos = Kosmos().useUnconfinedTestDispatcher()
+ private val repository = kosmos.activeNotificationListRepository
+ private val underTest = kosmos.ongoingCallInteractor
+
+ @Test
+ fun noNotification_emitsNoCall() = runTest {
+ val state by collectLastValue(underTest.ongoingCallState)
+ assertThat(state).isInstanceOf(OngoingCallModel.NoCall::class.java)
+ }
+
+ @Test
+ fun ongoingCallNotification_setsNotificationIconAndIntent() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.ongoingCallState)
+
+ // Set up notification with icon view and intent
+ val testIconView: StatusBarIconView = mock()
+ val testIntent: PendingIntent = mock()
+ repository.activeNotifications.value =
+ ActiveNotificationsStore.Builder()
+ .apply {
+ addIndividualNotif(
+ activeNotificationModel(
+ key = "notif1",
+ whenTime = 1000L,
+ callType = CallType.Ongoing,
+ statusBarChipIcon = testIconView,
+ contentIntent = testIntent
+ )
+ )
+ }
+ .build()
+
+ // Verify model is InCall and has the correct icon and intent.
+ assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+ val model = latest as OngoingCallModel.InCall
+ assertThat(model.notificationIconView).isSameInstanceAs(testIconView)
+ assertThat(model.intent).isSameInstanceAs(testIntent)
+ }
+
+ @Test
+ fun ongoingCallNotification_emitsInCall() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.ongoingCallState)
+
+ repository.activeNotifications.value =
+ ActiveNotificationsStore.Builder()
+ .apply {
+ addIndividualNotif(
+ activeNotificationModel(
+ key = "notif1", whenTime = 1000L, callType = CallType.Ongoing
+ )
+ )
+ }
+ .build()
+
+ assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+ }
+
+ @Test
+ fun notificationRemoved_emitsNoCall() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.ongoingCallState)
+
+ repository.activeNotifications.value =
+ ActiveNotificationsStore.Builder()
+ .apply {
+ addIndividualNotif(
+ activeNotificationModel(
+ key = "notif1", whenTime = 1000L, callType = CallType.Ongoing
+ )
+ )
+ }
+ .build()
+
+ repository.activeNotifications.value = ActiveNotificationsStore()
+ assertThat(latest).isInstanceOf(OngoingCallModel.NoCall::class.java)
+ }
+
+ @Test
+ fun ongoingCallNotification_appVisibleInitially_emitsInCallWithVisibleApp() =
+ kosmos.runTest {
+ kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = true
+ val latest by collectLastValue(underTest.ongoingCallState)
+
+ repository.activeNotifications.value =
+ ActiveNotificationsStore.Builder()
+ .apply {
+ addIndividualNotif(
+ activeNotificationModel(
+ key = "notif1",
+ whenTime = 1000L,
+ callType = CallType.Ongoing,
+ uid = UID
+ )
+ )
+ }
+ .build()
+
+ assertThat(latest).isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java)
+ }
+
+ @Test
+ fun ongoingCallNotification_appNotVisibleInitially_emitsInCall() =
+ kosmos.runTest {
+ kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false
+ val latest by collectLastValue(underTest.ongoingCallState)
+
+ repository.activeNotifications.value =
+ ActiveNotificationsStore.Builder()
+ .apply {
+ addIndividualNotif(
+ activeNotificationModel(
+ key = "notif1",
+ whenTime = 1000L,
+ callType = CallType.Ongoing,
+ uid = UID
+ )
+ )
+ }
+ .build()
+
+ assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+ }
+
+ @Test
+ fun ongoingCallNotification_visibilityChanges_updatesState() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.ongoingCallState)
+
+ // Start with notification and app not visible
+ kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false
+ repository.activeNotifications.value =
+ ActiveNotificationsStore.Builder()
+ .apply {
+ addIndividualNotif(
+ activeNotificationModel(
+ key = "notif1",
+ whenTime = 1000L,
+ callType = CallType.Ongoing,
+ uid = UID
+ )
+ )
+ }
+ .build()
+ assertThat(latest)
+ .isInstanceOf(OngoingCallModel.InCall::class.java)
+
+ // App becomes visible
+ kosmos.activityManagerRepository.fake.setIsAppVisible(UID, true)
+ assertThat(latest).isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java)
+
+ // App becomes invisible again
+ kosmos.activityManagerRepository.fake.setIsAppVisible(UID, false)
+ assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+ }
+
+ companion object {
+ private const val UID = 885
+ }
+}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bc81a4b..e417da4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3814,6 +3814,9 @@
shortcut helper The helper is a component that shows the user which keyboard shortcuts
they can use. [CHAR LIMIT=NONE] -->
<string name="shortcut_helper_customize_button_text">Customize</string>
+ <!-- Description text of the button that allows user to resets all custom shortcuts in keyboard
+ shortcut helper when in customization mode. [CHAR LIMIT=NONE] -->
+ <string name="shortcut_helper_reset_button_text">Reset</string>
<!-- Description text of the button that allows user to exit shortcut customization mode in
keyboard shortcut helper The helper is a component that shows the user which keyboard
shortcuts they can use. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 071cf8a..5af80cb 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -63,6 +63,7 @@
import com.android.systemui.plugins.clocks.ZenData
import com.android.systemui.plugins.clocks.ZenData.ZenMode
import com.android.systemui.res.R as SysuiR
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.regionsampling.RegionSampler
import com.android.systemui.statusbar.policy.BatteryController
@@ -466,6 +467,15 @@
batteryController.addCallback(batteryCallback)
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
zenModeController.addCallback(zenModeCallback)
+ if (SceneContainerFlag.isEnabled) {
+ handleDoze(
+ when (AOD) {
+ keyguardTransitionInteractor.getCurrentState() -> 1f
+ keyguardTransitionInteractor.getStartedState() -> 1f
+ else -> 0f
+ }
+ )
+ }
disposableHandle =
parent.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
index 1401678..37433ca 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
@@ -16,7 +16,9 @@
package com.android.systemui.keyboard.shortcut.shared.model
-data class ShortcutSubCategory(val label: String, val shortcuts: List<Shortcut>)
+data class ShortcutSubCategory(val label: String, val shortcuts: List<Shortcut>) {
+ val containsCustomShortcuts: Boolean = shortcuts.any { it.containsCustomShortcutCommands }
+}
class ShortcutSubCategoryBuilder(val label: String) {
private val shortcuts = mutableListOf<Shortcut>()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
index bd0430b..274fa59 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
@@ -53,15 +53,18 @@
override suspend fun onActivated(): Nothing {
viewModel.shortcutCustomizationUiState.collect { uiState ->
- val shouldShowAddDialog = uiState is AddShortcutDialog && !uiState.isDialogShowing
- val shouldShowDeleteDialog = uiState is DeleteShortcutDialog && !uiState.isDialogShowing
- val shouldShowResetDialog = uiState is ResetShortcutDialog && !uiState.isDialogShowing
- if (shouldShowDeleteDialog || shouldShowAddDialog || shouldShowResetDialog) {
- dialog = createDialog().also { it.show() }
- viewModel.onDialogShown()
- } else if (uiState is ShortcutCustomizationUiState.Inactive) {
- dialog?.dismiss()
- dialog = null
+ when(uiState){
+ is AddShortcutDialog,
+ is DeleteShortcutDialog,
+ is ResetShortcutDialog -> {
+ if (dialog == null){
+ dialog = createDialog().also { it.show() }
+ }
+ }
+ is ShortcutCustomizationUiState.Inactive -> {
+ dialog?.dismiss()
+ dialog = null
+ }
}
}
awaitCancellation()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index 7929307..2fdcf87 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -19,6 +19,7 @@
import android.graphics.drawable.Icon
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
@@ -56,6 +57,7 @@
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.DeleteOutline
import androidx.compose.material.icons.filled.ExpandMore
+import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Tune
import androidx.compose.material3.CenterAlignedTopAppBar
@@ -113,7 +115,6 @@
import androidx.compose.ui.util.fastForEachIndexed
import com.android.compose.modifiers.thenIf
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
-import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
@@ -125,6 +126,7 @@
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
import com.android.systemui.res.R
import kotlinx.coroutines.delay
+import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel
@Composable
fun ShortcutHelper(
@@ -187,6 +189,7 @@
onKeyboardSettingsClicked,
shortcutsUiState.isShortcutCustomizerFlagEnabled,
onCustomizationRequested,
+ shortcutsUiState.shouldShowResetButton
)
}
}
@@ -377,6 +380,7 @@
onKeyboardSettingsClicked: () -> Unit,
isShortcutCustomizerFlagEnabled: Boolean,
onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
+ shouldShowResetButton: Boolean
) {
val selectedCategory = categories.fastFirstOrNull { it.type == selectedCategoryType }
var isCustomizing by remember { mutableStateOf(false) }
@@ -389,11 +393,14 @@
TitleBar(isCustomizing)
}
if (isShortcutCustomizerFlagEnabled) {
- if (isCustomizing) {
- DoneButton(onClick = { isCustomizing = false })
- } else {
- CustomizeButton(onClick = { isCustomizing = true })
- }
+ CustomizationButtonsContainer(
+ isCustomizing = isCustomizing,
+ onToggleCustomizationMode = { isCustomizing = !isCustomizing },
+ onReset = {
+ onCustomizationRequested(ShortcutCustomizationRequestInfo.Reset)
+ },
+ shouldShowResetButton = shouldShowResetButton,
+ )
} else {
Spacer(modifier = Modifier.width(if (isCustomizing) 69.dp else 133.dp))
}
@@ -422,6 +429,38 @@
}
@Composable
+private fun CustomizationButtonsContainer(
+ isCustomizing: Boolean,
+ shouldShowResetButton: Boolean,
+ onToggleCustomizationMode: () -> Unit,
+ onReset: () -> Unit,
+) {
+ Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
+ if (isCustomizing) {
+ if (shouldShowResetButton) {
+ ResetButton(onClick = onReset)
+ }
+ DoneButton(onClick = onToggleCustomizationMode)
+ } else {
+ CustomizeButton(onClick = onToggleCustomizationMode)
+ }
+ }
+}
+
+@Composable
+private fun ResetButton(onClick: () -> Unit) {
+ ShortcutHelperButton(
+ onClick = onClick,
+ color = Color.Transparent,
+ width = 99.dp,
+ iconSource = IconSource(imageVector = Icons.Default.Refresh),
+ text = stringResource(id = R.string.shortcut_helper_reset_button_text),
+ contentColor = MaterialTheme.colorScheme.primary,
+ border = BorderStroke(color = MaterialTheme.colorScheme.outlineVariant, width = 1.dp),
+ )
+}
+
+@Composable
private fun CustomizeButton(onClick: () -> Unit) {
ShortcutHelperButton(
onClick = onClick,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
index 58ce194..55c0fe2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
@@ -228,74 +228,8 @@
contentColor: Color,
contentPaddingHorizontal: Dp = 16.dp,
contentPaddingVertical: Dp = 10.dp,
-) {
- ClickableShortcutSurface(
- onClick = onClick,
- shape = shape,
- color = color,
- modifier = modifier.semantics { role = Role.Button }.width(width).height(height),
- interactionsConfig =
- InteractionsConfig(
- hoverOverlayColor = MaterialTheme.colorScheme.onSurface,
- hoverOverlayAlpha = 0.11f,
- pressedOverlayColor = MaterialTheme.colorScheme.onSurface,
- pressedOverlayAlpha = 0.15f,
- focusOutlineColor = MaterialTheme.colorScheme.secondary,
- focusOutlineStrokeWidth = 3.dp,
- focusOutlinePadding = 2.dp,
- surfaceCornerRadius = 28.dp,
- focusOutlineCornerRadius = 33.dp,
- ),
- ) {
- Row(
- modifier =
- Modifier.padding(
- horizontal = contentPaddingHorizontal,
- vertical = contentPaddingVertical,
- ),
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.Center,
- ) {
- if (iconSource.imageVector != null) {
- Icon(
- tint = contentColor,
- imageVector = iconSource.imageVector,
- contentDescription = null,
- modifier = Modifier.size(20.dp).wrapContentSize(Alignment.Center),
- )
- }
-
- if (iconSource.imageVector != null && text != null) {
- Spacer(modifier = Modifier.weight(1f))
- }
-
- if (text != null) {
- Text(
- text,
- color = contentColor,
- fontSize = 14.sp,
- style = MaterialTheme.typography.labelLarge,
- modifier = Modifier.wrapContentSize(Alignment.Center),
- )
- }
- }
- }
-}
-
-@Composable
-fun ShortcutHelperButton(
- modifier: Modifier = Modifier,
- onClick: () -> Unit,
- shape: Shape = RoundedCornerShape(360.dp),
- color: Color,
- width: Dp,
- height: Dp = 40.dp,
- iconSource: IconSource = IconSource(),
- text: String? = null,
- contentColor: Color,
- contentPaddingHorizontal: Dp = 16.dp,
- contentPaddingVertical: Dp = 10.dp,
enabled: Boolean = true,
+ border: BorderStroke? = null,
) {
ShortcutHelperButtonSurface(
onClick = onClick,
@@ -305,6 +239,7 @@
enabled = enabled,
width = width,
height = height,
+ border = border,
) {
Row(
modifier =
@@ -342,7 +277,7 @@
}
@Composable
-fun ShortcutHelperButtonSurface(
+private fun ShortcutHelperButtonSurface(
onClick: () -> Unit,
shape: Shape,
color: Color,
@@ -350,6 +285,7 @@
enabled: Boolean,
width: Dp,
height: Dp,
+ border: BorderStroke?,
content: @Composable () -> Unit,
) {
if (enabled) {
@@ -357,6 +293,7 @@
onClick = onClick,
shape = shape,
color = color,
+ border = border,
modifier = modifier.semantics { role = Role.Button }.width(width).height(height),
interactionsConfig =
InteractionsConfig(
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCategoryUi.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCategoryUi.kt
index f5d478b..2728772 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCategoryUi.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCategoryUi.kt
@@ -31,4 +31,6 @@
iconSource: IconSource,
shortcutCategory: ShortcutCategory,
) : this(label, iconSource, shortcutCategory.type, shortcutCategory.subCategories)
+
+ val containsCustomShortcuts: Boolean = subCategories.any { it.containsCustomShortcuts }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
index bfc9486..36c5ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
@@ -23,17 +23,12 @@
val shortcutLabel: String,
val errorMessage: String = "",
val defaultCustomShortcutModifierKey: ShortcutKey.Icon.ResIdIcon,
- val isDialogShowing: Boolean = false,
val pressedKeys: List<ShortcutKey> = emptyList(),
) : ShortcutCustomizationUiState
- data class DeleteShortcutDialog(
- val isDialogShowing: Boolean = false
- ) : ShortcutCustomizationUiState
+ data object DeleteShortcutDialog : ShortcutCustomizationUiState
- data class ResetShortcutDialog(
- val isDialogShowing: Boolean = false
- ) : ShortcutCustomizationUiState
+ data object ResetShortcutDialog : ShortcutCustomizationUiState
data object Inactive : ShortcutCustomizationUiState
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt
index 02b0b43..52ab157 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt
@@ -25,6 +25,7 @@
val shortcutCategories: List<ShortcutCategoryUi>,
val defaultSelectedCategory: ShortcutCategoryType?,
val isShortcutCustomizerFlagEnabled: Boolean = false,
+ val shouldShowResetButton: Boolean = false,
) : ShortcutsUiState
data object Inactive : ShortcutsUiState
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
index 76a2e60..92e2592 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
@@ -73,32 +73,22 @@
shortcutLabel = requestInfo.label,
defaultCustomShortcutModifierKey =
shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey(),
- isDialogShowing = false,
pressedKeys = emptyList(),
)
shortcutCustomizationInteractor.onCustomizationRequested(requestInfo)
}
is ShortcutCustomizationRequestInfo.Delete -> {
- _shortcutCustomizationUiState.value = DeleteShortcutDialog(isDialogShowing = false)
+ _shortcutCustomizationUiState.value = DeleteShortcutDialog
shortcutCustomizationInteractor.onCustomizationRequested(requestInfo)
}
ShortcutCustomizationRequestInfo.Reset -> {
- _shortcutCustomizationUiState.value = ResetShortcutDialog(isDialogShowing = false)
+ _shortcutCustomizationUiState.value = ResetShortcutDialog
}
}
}
- fun onDialogShown() {
- _shortcutCustomizationUiState.update { uiState ->
- (uiState as? AddShortcutDialog)?.copy(isDialogShowing = true)
- ?: (uiState as? DeleteShortcutDialog)?.copy(isDialogShowing = true)
- ?: (uiState as? ResetShortcutDialog)?.copy(isDialogShowing = true)
- ?: uiState
- }
- }
-
fun onDialogDismissed() {
_shortcutCustomizationUiState.value = ShortcutCustomizationUiState.Inactive
shortcutCustomizationInteractor.onCustomizationRequested(null)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
index 08fd0af8..0f5f073 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyboard.shortcut.ui.viewmodel
import android.app.role.RoleManager
+import android.content.Context
import android.content.pm.PackageManager.NameNotFoundException
import android.util.Log
import androidx.compose.material.icons.Icons
@@ -40,7 +41,6 @@
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
-import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
@@ -51,10 +51,12 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
+import javax.inject.Inject
class ShortcutHelperViewModel
@Inject
constructor(
+ private val context: Context,
private val roleManager: RoleManager,
private val userTracker: UserTracker,
@Background private val backgroundScope: CoroutineScope,
@@ -88,6 +90,7 @@
shortcutCategories = shortcutCategoriesUi,
defaultSelectedCategory = getDefaultSelectedCategory(filteredCategories),
isShortcutCustomizerFlagEnabled = keyboardShortcutHelperShortcutCustomizer(),
+ shouldShowResetButton = shouldShowResetButton(shortcutCategoriesUi)
)
}
}
@@ -97,6 +100,10 @@
initialValue = ShortcutsUiState.Inactive,
)
+ private fun shouldShowResetButton(categoriesUi: List<ShortcutCategoryUi>): Boolean {
+ return categoriesUi.any { it.containsCustomShortcuts }
+ }
+
private fun convertCategoriesModelToUiModel(
categories: List<ShortcutCategory>
): List<ShortcutCategoryUi> {
@@ -136,13 +143,13 @@
private fun getShortcutCategoryLabel(type: ShortcutCategoryType): String =
when (type) {
ShortcutCategoryType.System ->
- userContext.getString(R.string.shortcut_helper_category_system)
+ context.getString(R.string.shortcut_helper_category_system)
ShortcutCategoryType.MultiTasking ->
- userContext.getString(R.string.shortcut_helper_category_multitasking)
+ context.getString(R.string.shortcut_helper_category_multitasking)
ShortcutCategoryType.InputMethodEditor ->
- userContext.getString(R.string.shortcut_helper_category_input)
+ context.getString(R.string.shortcut_helper_category_input)
ShortcutCategoryType.AppCategories ->
- userContext.getString(R.string.shortcut_helper_category_app_shortcuts)
+ context.getString(R.string.shortcut_helper_category_app_shortcuts)
is CurrentApp -> getApplicationLabelForCurrentApp(type)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt
index 1def7b3..636f703 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt
@@ -19,7 +19,6 @@
import android.content.res.Resources
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.res.R
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.kotlin.emitOnStart
@@ -30,7 +29,7 @@
class QuickQuickSettingsRowRepository
@Inject
constructor(
- @Main private val resources: Resources,
+ @ShadeDisplayAware private val resources: Resources,
@ShadeDisplayAware configurationRepository: ConfigurationRepository,
) {
val rows =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
index 75debb6..9efdd98 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
@@ -9,6 +9,7 @@
import android.service.quicksettings.Tile
import android.text.TextUtils
import android.text.format.DateFormat
+import android.widget.Button
import androidx.annotation.VisibleForTesting
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.MetricsLogger
@@ -70,7 +71,10 @@
}
override fun newTileState(): QSTile.State {
- return QSTile.State().apply { handlesLongClick = false }
+ return QSTile.State().apply {
+ handlesLongClick = false
+ expandedAccessibilityClassName = Button::class.java.name
+ }
}
override fun handleClick(expandable: Expandable?) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index 404ace1..7213f7a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -21,6 +21,7 @@
import android.os.Handler
import android.os.Looper
import android.service.quicksettings.Tile
+import android.widget.Button
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.MetricsLogger
import com.android.systemui.animation.Expandable
@@ -163,6 +164,7 @@
} else {
state.state = Tile.STATE_UNAVAILABLE
}
+ state.expandedAccessibilityClassName = Button::class.java.name
}
override fun getMetricsCategory(): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
index 374bcda..e37ed16 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
@@ -32,6 +32,7 @@
import android.service.quicksettings.Tile;
import android.text.TextUtils;
import android.util.Log;
+import android.widget.Switch;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -176,6 +177,7 @@
} else {
state.state = isDreaming() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
}
+ state.expandedAccessibilityClassName = Switch.class.getName();
}
@Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
index 48b39dc..74563ff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
@@ -24,6 +24,7 @@
import android.os.UserManager;
import android.provider.Settings;
import android.service.quicksettings.Tile;
+import android.widget.Button;
import androidx.annotation.Nullable;
@@ -124,6 +125,7 @@
state.state = Tile.STATE_INACTIVE;
state.secondaryLabel = "";
}
+ state.expandedAccessibilityClassName = Button.class.getName();
}
@Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index e9c5f4a..0a59529 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -30,7 +30,7 @@
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
-import android.widget.Switch;
+import android.widget.Button;
import androidx.annotation.Nullable;
@@ -136,7 +136,7 @@
}
@Override
- public void secondaryClick(@Nullable Expandable expandable) {
+ public void handleSecondaryClick(@Nullable Expandable expandable) {
// TODO(b/358352265): Figure out the correct action for the secondary click
// Toggle Wifi
mWifiStateWorker.setWifiEnabled(!mWifiStateWorker.isWifiEnabled());
@@ -577,7 +577,7 @@
state.contentDescription = minimalContentDescription.toString();
state.dualLabelContentDescription = r.getString(
R.string.accessibility_quick_settings_open_settings, getTileLabel());
- state.expandedAccessibilityClassName = Switch.class.getName();
+ state.expandedAccessibilityClassName = Button.class.getName();
if (DEBUG) {
Log.d(TAG, "handleUpdateWifiState: " + "BooleanState = " + state.toString());
}
@@ -594,7 +594,7 @@
boolean mobileDataEnabled = mDataController.isMobileDataSupported()
&& mDataController.isMobileDataEnabled();
state.value = mobileDataEnabled;
- state.expandedAccessibilityClassName = Switch.class.getName();
+ state.expandedAccessibilityClassName = Button.class.getName();
if (cb.mAirplaneModeEnabled && cb.mQsTypeIcon != TelephonyIcons.ICON_CWF) {
state.state = Tile.STATE_INACTIVE;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
index 7225800..6d3e5d0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
@@ -20,7 +20,7 @@
import android.os.Handler
import android.os.Looper
import android.provider.Settings
-import android.widget.Switch
+import android.widget.Button
import com.android.internal.logging.MetricsLogger
import com.android.systemui.animation.Expandable
import com.android.systemui.dagger.qualifiers.Background
@@ -71,7 +71,7 @@
metricsLogger,
statusBarStateController,
activityStarter,
- qsLogger
+ qsLogger,
) {
private var model: InternetTileModel = viewModel.tileModel.value
@@ -110,7 +110,7 @@
return InternetDetailsViewModel { longClick(null) }
}
- override fun secondaryClick(expandable: Expandable?) {
+ override fun handleSecondaryClick(expandable: Expandable?) {
// TODO(b/358352265): Figure out the correct action for the secondary click
// Toggle wifi
wifiStateWorker.isWifiEnabled = !wifiStateWorker.isWifiEnabled
@@ -118,7 +118,7 @@
override fun handleUpdateState(state: QSTile.BooleanState, arg: Any?) {
state.label = mContext.resources.getString(R.string.quick_settings_internet_label)
- state.expandedAccessibilityClassName = Switch::class.java.name
+ state.expandedAccessibilityClassName = Button::class.java.name
model.applyTo(state, mContext)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
index 93a51cf..467233d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
@@ -21,6 +21,7 @@
import android.os.Looper;
import android.service.quicksettings.Tile;
import android.util.Log;
+import android.widget.Button;
import androidx.annotation.Nullable;
@@ -126,6 +127,7 @@
// would go to "Unavailable" state only when GMS core is updating.
state.secondaryLabel = state.state == Tile.STATE_UNAVAILABLE
? mContext.getString(R.string.qr_code_scanner_updating_secondary_label) : null;
+ state.expandedAccessibilityClassName = Button.class.getName();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index 04e72d5..6deb192 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -40,6 +40,7 @@
import android.service.quickaccesswallet.WalletCard;
import android.service.quicksettings.Tile;
import android.util.Log;
+import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -186,6 +187,7 @@
state.secondaryLabel = null;
state.sideViewCustomDrawable = null;
}
+ state.expandedAccessibilityClassName = Button.class.getName();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
index 87f542e..aeb6cef 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.base.viewmodel
import android.os.UserHandle
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.Dumpable
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
@@ -58,11 +59,8 @@
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest
-import com.android.app.tracing.coroutines.launchTraced as launch
-import kotlinx.coroutines.withContext
/**
* Provides a hassle-free way to implement new tiles according to current System UI architecture
@@ -90,36 +88,35 @@
private val users: MutableStateFlow<UserHandle> =
MutableStateFlow(userRepository.getSelectedUserInfo().userHandle)
+
private val userInputs: MutableSharedFlow<QSTileUserAction> = MutableSharedFlow()
+
private val forceUpdates: MutableSharedFlow<Unit> = MutableSharedFlow()
private val spec
get() = config.tileSpec
- private val tileData: SharedFlow<DATA_TYPE> = createTileDataFlow()
+ private val tileData: SharedFlow<DATA_TYPE?> = createTileDataFlow()
override val state: StateFlow<QSTileState?> =
tileData
.map { data ->
- withContext(uiBackgroundDispatcher) { mapper().map(config, data) }
- .also { state -> qsTileLogger.logStateUpdate(spec, state, data) }
+ data?.let {
+ mapper().map(config, it).also { state ->
+ qsTileLogger.logStateUpdate(spec, state, it)
+ }
+ }
}
- .stateIn(
- tileScope,
- SharingStarted.WhileSubscribed(),
- null,
- )
+ .flowOn(uiBackgroundDispatcher)
+ .stateIn(tileScope, SharingStarted.WhileSubscribed(), null)
+
override val isAvailable: StateFlow<Boolean> =
users
.flatMapLatest { tileDataInteractor().availability(it) }
.flowOn(backgroundDispatcher)
- .stateIn(
- tileScope,
- SharingStarted.WhileSubscribed(),
- true,
- )
+ .stateIn(tileScope, SharingStarted.WhileSubscribed(), true)
override fun forceUpdate() {
- tileScope.launch { forceUpdates.emit(Unit) }
+ tileScope.launch(context = backgroundDispatcher) { forceUpdates.emit(Unit) }
}
override fun onUserChanged(user: UserHandle) {
@@ -131,9 +128,9 @@
userAction,
spec,
tileData.replayCache.isNotEmpty(),
- state.replayCache.isNotEmpty()
+ state.replayCache.isNotEmpty(),
)
- tileScope.launch { userInputs.emit(userAction) }
+ tileScope.launch(context = backgroundDispatcher) { userInputs.emit(userAction) }
}
override fun destroy() {
@@ -147,7 +144,7 @@
println(state.replayCache.lastOrNull().toString())
}
- private fun createTileDataFlow(): SharedFlow<DATA_TYPE> =
+ private fun createTileDataFlow(): SharedFlow<DATA_TYPE?> =
users
.transformLatest { user ->
coroutineScope {
@@ -159,6 +156,7 @@
.onEach { qsTileLogger.logForceUpdate(spec) },
)
.onStart { qsTileLogger.logInitialRequest(spec) }
+ .flowOn(backgroundDispatcher)
.stateIn(this, SharingStarted.Eagerly, DataUpdateTrigger.InitialRequest)
tileDataInteractor()
.tileData(user, updateTriggers)
@@ -171,11 +169,8 @@
}
}
.distinctUntilChanged()
- .shareIn(
- tileScope,
- SharingStarted.WhileSubscribed(),
- replay = 1, // we only care about the most recent value
- )
+ .flowOn(backgroundDispatcher)
+ .stateIn(tileScope, SharingStarted.WhileSubscribed(), null)
/**
* Creates a user input flow which:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
index bb0467f..2eae3eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
@@ -23,6 +23,8 @@
import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
import com.android.systemui.statusbar.chips.StatusBarChipsLog
import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository
+import com.android.systemui.statusbar.phone.ongoingcall.domain.interactor.OngoingCallInteractor
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -37,17 +39,30 @@
@Inject
constructor(
@Application private val scope: CoroutineScope,
+ ongoingCallInteractor: OngoingCallInteractor,
repository: OngoingCallRepository,
@StatusBarChipsLog private val logger: LogBuffer,
) {
val ongoingCallState: StateFlow<OngoingCallModel> =
- repository.ongoingCallState
+ (if (StatusBarChipsModernization.isEnabled)
+ ongoingCallInteractor.ongoingCallState
+ else
+ repository.ongoingCallState)
.onEach {
- logger.log(TAG, LogLevel.INFO, { str1 = it::class.simpleName }, { "State: $str1" })
+ logger.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = it::class.simpleName },
+ { "State: $str1" }
+ )
}
- .stateIn(scope, SharingStarted.Lazily, OngoingCallModel.NoCall)
+ .stateIn(
+ scope,
+ SharingStarted.Lazily,
+ OngoingCallModel.NoCall
+ )
companion object {
private val TAG = "OngoingCall".pad()
}
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index b8cdd25..6f491e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -59,7 +59,8 @@
interactor.ongoingCallState
.map { state ->
when (state) {
- is OngoingCallModel.NoCall -> OngoingActivityChipModel.Hidden()
+ is OngoingCallModel.NoCall,
+ is OngoingCallModel.InCallWithVisibleApp -> OngoingActivityChipModel.Hidden()
is OngoingCallModel.InCall -> {
val icon =
if (
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
index 087b510..c57c807 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
@@ -105,7 +105,7 @@
}
return null
}
- return NotificationChipModel(key, statusBarChipIconView)
+ return NotificationChipModel(key, statusBarChipIconView, whenTime)
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
index 5698ee6..bc4241d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
@@ -19,4 +19,8 @@
import com.android.systemui.statusbar.StatusBarIconView
/** Modeling all the data needed to render a status bar notification chip. */
-data class NotificationChipModel(val key: String, val statusBarChipIconView: StatusBarIconView)
+data class NotificationChipModel(
+ val key: String,
+ val statusBarChipIconView: StatusBarIconView,
+ val whenTime: Long,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
index 9eff627..b2f7e2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
@@ -63,9 +63,13 @@
)
}
}
- return OngoingActivityChipModel.Shown.IconOnly(icon, colors, onClickListener)
+ return OngoingActivityChipModel.Shown.ShortTimeDelta(
+ icon,
+ colors,
+ time = this.whenTime,
+ onClickListener,
+ )
// TODO(b/364653005): Use Notification.showWhen to determine if we should show the time.
- // TODO(b/364653005): If Notification.whenTime is in the past, show "ago" in the text.
// TODO(b/364653005): If Notification.shortCriticalText is set, use that instead of `when`.
// TODO(b/364653005): If the app that posted the notification is in the foreground, don't
// show that app's chip.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
index f4462a4..730784a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
@@ -192,10 +192,14 @@
}
is OngoingActivityChipModel.Shown.ShortTimeDelta -> {
chipShortTimeDeltaView.setTime(chipModel.time)
- // TODO(b/364653005): DateTimeView's relative time doesn't quite match the format we
- // want in the status bar chips.
- chipShortTimeDeltaView.isShowRelativeTime = true
chipShortTimeDeltaView.visibility = View.VISIBLE
+ chipShortTimeDeltaView.isShowRelativeTime = true
+ chipShortTimeDeltaView.setRelativeTimeDisambiguationTextMask(
+ DateTimeView.DISAMBIGUATION_TEXT_PAST
+ )
+ chipShortTimeDeltaView.setRelativeTimeUnitDisplayLength(
+ DateTimeView.UNIT_DISPLAY_LENGTH_MEDIUM
+ )
chipTextView.visibility = View.GONE
chipTimeView.hide()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index 47b695e..2588c7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -36,6 +36,7 @@
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.ui.SystemBarUtilsProxyImpl
import com.android.systemui.statusbar.window.MultiDisplayStatusBarWindowControllerStore
@@ -63,11 +64,6 @@
@Binds
@IntoMap
- @ClassKey(OngoingCallController::class)
- fun bindOngoingCallController(impl: OngoingCallController): CoreStartable
-
- @Binds
- @IntoMap
@ClassKey(LightBarController::class)
fun lightBarControllerAsCoreStartable(controller: LightBarController): CoreStartable
@@ -90,6 +86,18 @@
): LightBarController.Factory
companion object {
+ @Provides
+ @SysUISingleton
+ @IntoMap
+ @ClassKey(OngoingCallController::class)
+ fun ongoingCallController(
+ controller: OngoingCallController
+ ): CoreStartable =
+ if (StatusBarChipsModernization.isEnabled) {
+ CoreStartable.NOP
+ } else {
+ controller
+ }
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 6de4928..e4768e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -71,6 +71,7 @@
import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent.Startable;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization;
import com.android.systemui.statusbar.phone.ui.DarkIconManager;
import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.pipeline.shared.ui.binder.HomeStatusBarViewBinder;
@@ -960,7 +961,9 @@
mOngoingCallController.addCallback(mOngoingCallListener);
}
// TODO(b/364653005): Do we also need to set the secondary activity chip?
- mOngoingCallController.setChipView(mPrimaryOngoingActivityChip);
+ if (!StatusBarChipsModernization.isEnabled()) {
+ mOngoingCallController.setChipView(mPrimaryOngoingActivityChip);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 78926c7..2166304 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -60,7 +60,10 @@
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-/** A controller to handle the ongoing call chip in the collapsed status bar. */
+/** A controller to handle the ongoing call chip in the collapsed status bar.
+ * @deprecated Use [OngoingCallInteractor] instead, which follows recommended architecture patterns
+ */
+@Deprecated("Use OngoingCallInteractor instead")
@SysUISingleton
class OngoingCallController
@Inject
@@ -165,6 +168,9 @@
}
override fun start() {
+ if (StatusBarChipsModernization.isEnabled)
+ return
+
dumpManager.registerDumpable(this)
if (Flags.statusBarUseReposForCallChip()) {
@@ -201,6 +207,8 @@
* [com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment].
*/
fun setChipView(chipView: View) {
+ StatusBarChipsModernization.assertInLegacyMode()
+
tearDownChipView()
this.chipView = chipView
val backgroundView: ChipBackgroundContainer? =
@@ -217,6 +225,8 @@
* Returns true if there's an active ongoing call that should be displayed in a status bar chip.
*/
fun hasOngoingCall(): Boolean {
+ StatusBarChipsModernization.assertInLegacyMode()
+
return callNotificationInfo?.isOngoing == true &&
// When the user is in the phone app, don't show the chip.
!uidObserver.isCallAppVisible
@@ -224,6 +234,8 @@
/** Creates the right [OngoingCallModel] based on the call state. */
private fun getOngoingCallModel(): OngoingCallModel {
+ StatusBarChipsModernization.assertInLegacyMode()
+
if (hasOngoingCall()) {
val currentInfo =
callNotificationInfo
@@ -255,6 +267,8 @@
}
override fun addCallback(listener: OngoingCallListener) {
+ StatusBarChipsModernization.assertInLegacyMode()
+
synchronized(mListeners) {
if (!mListeners.contains(listener)) {
mListeners.add(listener)
@@ -263,10 +277,14 @@
}
override fun removeCallback(listener: OngoingCallListener) {
+ StatusBarChipsModernization.assertInLegacyMode()
+
synchronized(mListeners) { mListeners.remove(listener) }
}
private fun updateInfoFromNotifModel(notifModel: ActiveNotificationModel?) {
+ StatusBarChipsModernization.assertInLegacyMode()
+
if (notifModel == null) {
logger.log(TAG, LogLevel.DEBUG, {}, { "NotifInteractorCallModel: null" })
removeChip()
@@ -310,6 +328,8 @@
}
private fun updateChip() {
+ StatusBarChipsModernization.assertInLegacyMode()
+
val currentCallNotificationInfo = callNotificationInfo ?: return
val currentChipView = chipView
@@ -360,6 +380,8 @@
}
private fun updateChipClickListener() {
+ StatusBarChipsModernization.assertInLegacyMode()
+
if (Flags.statusBarScreenSharingChips()) {
return
}
@@ -386,10 +408,14 @@
/** Returns true if the given [procState] represents a process that's visible to the user. */
private fun isProcessVisibleToUser(procState: Int): Boolean {
+ StatusBarChipsModernization.assertInLegacyMode()
+
return procState <= ActivityManager.PROCESS_STATE_TOP
}
private fun updateGestureListening() {
+ StatusBarChipsModernization.assertInLegacyMode()
+
if (
callNotificationInfo == null ||
callNotificationInfo?.statusBarSwipedAway == true ||
@@ -404,6 +430,8 @@
}
private fun removeChip() {
+ StatusBarChipsModernization.assertInLegacyMode()
+
callNotificationInfo = null
if (!Flags.statusBarScreenSharingChips()) {
tearDownChipView()
@@ -432,6 +460,8 @@
* detected.
*/
private fun onSwipeAwayGestureDetected() {
+ StatusBarChipsModernization.assertInLegacyMode()
+
logger.log(TAG, LogLevel.DEBUG, {}, { "Swipe away gesture detected" })
callNotificationInfo = callNotificationInfo?.copy(statusBarSwipedAway = true)
statusBarWindowControllerStore.defaultDisplay.setOngoingProcessRequiresStatusBarVisible(
@@ -441,6 +471,8 @@
}
private fun sendStateChangeEvent() {
+ StatusBarChipsModernization.assertInLegacyMode()
+
ongoingCallRepository.setOngoingCallState(getOngoingCallModel())
mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt
new file mode 100644
index 0000000..2ab2b68
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt
@@ -0,0 +1,52 @@
+/*
+* Copyright (C) 2024 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.android.systemui.statusbar.phone.ongoingcall
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the status_bar_use_interactor_for_call_chip flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object StatusBarChipsModernization {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_STATUS_BAR_CHIPS_MODERNIZATION
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.statusBarChipsModernization() && Flags.statusBarRootModernization()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
index f16371a..b932c71a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
@@ -20,6 +20,7 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
@@ -33,7 +34,9 @@
* [com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController] and
* [com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore]. Instead, those two
* classes both refer to this repository.
+ * @deprecated Use [OngoingCallInteractor] instead.
*/
+@Deprecated("Use OngoingCallInteractor instead")
@SysUISingleton
class OngoingCallRepository
@Inject
@@ -49,6 +52,8 @@
* [com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController].
*/
fun setOngoingCallState(state: OngoingCallModel) {
+ StatusBarChipsModernization.assertInLegacyMode()
+
logger.log(
TAG,
LogLevel.DEBUG,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
new file mode 100644
index 0000000..1f7bd14
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.ongoingcall.domain.interactor
+
+import com.android.systemui.activity.data.repository.ActivityManagerRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.Logger
+import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Interactor for determining whether to show a chip in the status bar for ongoing phone calls.
+ *
+ * This class monitors call notifications and the visibility of call apps to determine the appropriate
+ * chip state. It emits:
+ * * - [OngoingCallModel.NoCall] when there is no call notification
+ * * - [OngoingCallModel.InCallWithVisibleApp] when there is a call notification but the call app is visible
+ * * - [OngoingCallModel.InCall] when there is a call notification and the call app is not visible
+ * */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class OngoingCallInteractor @Inject constructor(
+ @Application private val scope: CoroutineScope,
+ activityManagerRepository: ActivityManagerRepository,
+ activeNotificationsInteractor: ActiveNotificationsInteractor,
+ @OngoingCallLog private val logBuffer: LogBuffer,
+) {
+ private val logger = Logger(logBuffer, TAG)
+
+ /**
+ * The current state of ongoing calls.
+ */
+ val ongoingCallState: StateFlow<OngoingCallModel> =
+ activeNotificationsInteractor.ongoingCallNotification
+ .flatMapLatest { notificationModel ->
+ when (notificationModel) {
+ null -> {
+ logger.d("No active call notification - hiding chip")
+ flowOf(OngoingCallModel.NoCall)
+ }
+
+ else -> combine(
+ flowOf(notificationModel),
+ activityManagerRepository.createIsAppVisibleFlow(
+ creationUid = notificationModel.uid,
+ logger = logger,
+ identifyingLogTag = TAG,
+ ),
+ ) { model, isVisible ->
+ when {
+ isVisible -> {
+ logger.d({ "Call app is visible: uid=$int1" }) {
+ int1 = model.uid
+ }
+ OngoingCallModel.InCallWithVisibleApp
+ }
+
+ else -> {
+ logger.d({ "Active call detected: startTime=$long1 hasIcon=$bool1" }) {
+ long1 = model.whenTime
+ bool1 = model.statusBarChipIconView != null
+ }
+ OngoingCallModel.InCall(
+ startTimeMs = model.whenTime,
+ notificationIconView = model.statusBarChipIconView,
+ intent = model.contentIntent,
+ )
+ }
+ }
+ }
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingCallModel.NoCall)
+
+ companion object {
+ private val TAG = "OngoingCall"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
index 34bff80..c2c91b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
@@ -25,6 +25,12 @@
data object NoCall : OngoingCallModel
/**
+ * There is an ongoing call but the call app is currently visible, so we don't need to show
+ * the chip.
+ */
+ data object InCallWithVisibleApp : OngoingCallModel
+
+ /**
* There *is* an ongoing call.
*
* @property startTimeMs the time that the phone call started, based on the notification's
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
index 1e8b016..812e0eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
@@ -41,6 +41,7 @@
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.statusbar.phone.ui.DarkIconManager
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.pipeline.shared.ui.binder.HomeStatusBarViewBinder
@@ -150,12 +151,11 @@
)
iconController.addIconGroup(darkIconManager)
- // TODO(b/372657935): This won't be needed once OngoingCallController is
- // implemented in recommended architecture
- ongoingCallController.setChipView(
- phoneStatusBarView.requireViewById(R.id.ongoing_activity_chip_primary)
- )
-
+ if (!StatusBarChipsModernization.isEnabled) {
+ ongoingCallController.setChipView(
+ phoneStatusBarView.requireViewById(R.id.ongoing_activity_chip_primary)
+ )
+ }
// For notifications, first inflate the [NotificationIconContainer]
val notificationIconArea =
phoneStatusBarView.requireViewById<ViewGroup>(R.id.notification_icon_area)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index d1e4f64..3e24fbe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -68,6 +68,7 @@
import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization;
import com.android.systemui.statusbar.phone.ui.DarkIconManager;
import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeHomeStatusBarViewBinder;
@@ -155,9 +156,9 @@
any(StatusBarWindowStateListener.class));
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void testDisableNone() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void testDisableNone() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
@@ -166,9 +167,9 @@
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void testDisableSystemInfo_systemAnimationIdle_doesHide() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void testDisableSystemInfo_systemAnimationIdle_doesHide() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
@@ -184,9 +185,9 @@
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void testSystemStatusAnimation_startedDisabled_finishedWithAnimator_showsSystemInfo() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void testSystemStatusAnimation_startedDisabled_finishedWithAnimator_showsSystemInfo() {
// GIVEN the status bar hides the system info via disable flags, while there is no event
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
@@ -214,9 +215,9 @@
assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void testSystemStatusAnimation_systemInfoDisabled_staysInvisible() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void testSystemStatusAnimation_systemInfoDisabled_staysInvisible() {
// GIVEN the status bar hides the system info via disable flags, while there is no event
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
@@ -231,9 +232,9 @@
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void testSystemStatusAnimation_notDisabled_animatesAlphaZero() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void testSystemStatusAnimation_notDisabled_animatesAlphaZero() {
// GIVEN the status bar is not disabled
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
@@ -247,9 +248,9 @@
assertEquals(0, getEndSideContentView().getAlpha(), 0.01);
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void testSystemStatusAnimation_notDisabled_animatesBackToAlphaOne() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void testSystemStatusAnimation_notDisabled_animatesBackToAlphaOne() {
// GIVEN the status bar is not disabled
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
@@ -271,9 +272,9 @@
assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void testDisableNotifications() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void testDisableNotifications() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
@@ -307,9 +308,9 @@
assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void testDisableClock() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void testDisableClock() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
@@ -343,10 +344,10 @@
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
- @Test
- @DisableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_shadeOpenAndShouldHide_everythingHidden() {
+ @Test
+ @DisableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_shadeOpenAndShouldHide_everythingHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// WHEN the shade is open and configured to hide the status bar icons
@@ -361,10 +362,10 @@
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
- @Test
- @DisableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_shadeOpenButNotShouldHide_everythingShown() {
+ @Test
+ @DisableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_shadeOpenButNotShouldHide_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// WHEN the shade is open but *not* configured to hide the status bar icons
@@ -379,11 +380,11 @@
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
- /** Regression test for b/279790651. */
- @Test
- @DisableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_shadeOpenAndShouldHide_thenShadeNotOpenAndDozingUpdate_everythingShown() {
+ /** Regression test for b/279790651. */
+ @Test
+ @DisableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_shadeOpenAndShouldHide_thenShadeNotOpenAndDozingUpdate_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// WHEN the shade is open and configured to hide the status bar icons
@@ -409,9 +410,9 @@
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_notTransitioningToOccluded_everythingShown() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_notTransitioningToOccluded_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
mCollapsedStatusBarViewModel.isTransitioningFromLockscreenToOccluded().setValue(false);
@@ -424,10 +425,10 @@
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
- @Test
- @DisableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_isTransitioningToOccluded_everythingHidden() {
+ @Test
+ @DisableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_isTransitioningToOccluded_everythingHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
mCollapsedStatusBarViewModel.isTransitioningFromLockscreenToOccluded().setValue(true);
@@ -440,10 +441,10 @@
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
- @Test
- @DisableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_wasTransitioningToOccluded_transitionFinished_everythingShown() {
+ @Test
+ @DisableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_wasTransitioningToOccluded_transitionFinished_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// WHEN the transition is occurring
@@ -472,9 +473,13 @@
assertEquals(View.GONE, getUserChipView().getVisibility());
}
- @Test
- @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
- public void disable_noOngoingCall_chipHidden() {
+ @Test
+ @DisableFlags({
+ FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void disable_noOngoingCall_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
@@ -484,9 +489,13 @@
assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
- @Test
- @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
- public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() {
+ @Test
+ @DisableFlags({
+ FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
@@ -497,9 +506,13 @@
assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
- @Test
- @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
- public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() {
+ @Test
+ @DisableFlags({
+ FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
@@ -510,9 +523,13 @@
assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
- @Test
- @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
- public void disable_hasOngoingCallButAlsoHun_chipHidden() {
+ @Test
+ @DisableFlags({
+ FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void disable_hasOngoingCallButAlsoHun_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
@@ -523,9 +540,13 @@
assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
- @Test
- @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
- public void disable_ongoingCallEnded_chipHidden() {
+ @Test
+ @DisableFlags({
+ FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void disable_ongoingCallEnded_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// Ongoing call started
@@ -547,9 +568,13 @@
assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
}
- @Test
- @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
- public void disable_hasOngoingCall_hidesNotifsWithoutAnimation() {
+ @Test
+ @DisableFlags({
+ FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void disable_hasOngoingCall_hidesNotifsWithoutAnimation() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// Enable animations for testing so that we can verify we still aren't animating
fragment.enableAnimationsForTesting();
@@ -564,9 +589,13 @@
assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
- @Test
- @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
- public void screenSharingChipsDisabled_ignoresNewCallback() {
+ @Test
+ @DisableFlags({
+ FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void screenSharingChipsDisabled_ignoresNewCallback() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// WHEN there *is* an ongoing call via old callback
@@ -597,10 +626,10 @@
assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void noOngoingActivity_chipHidden() {
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void noOngoingActivity_chipHidden() {
resumeAndGetFragment();
// TODO(b/332662551): We *should* be able to just set a value on
@@ -615,10 +644,10 @@
assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void hasPrimaryOngoingActivity_primaryChipDisplayedAndNotificationIconsHidden() {
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void hasPrimaryOngoingActivity_primaryChipDisplayedAndNotificationIconsHidden() {
resumeAndGetFragment();
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -630,12 +659,14 @@
assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
- @Test
- @EnableFlags({
- FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
- StatusBarNotifChips.FLAG_NAME,
- StatusBarRootModernization.FLAG_NAME})
- public void hasPrimaryOngoingActivity_viewsUnchangedWhenRootModernizationFlagOn() {
+ @Test
+ @EnableFlags({
+ FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+ StatusBarNotifChips.FLAG_NAME,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void hasPrimaryOngoingActivity_viewsUnchangedWhenRootModernizationFlagOn() {
resumeAndGetFragment();
assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
@@ -658,10 +689,14 @@
assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
}
- @Test
- @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
- public void hasSecondaryOngoingActivity_butNotifsFlagOff_secondaryChipHidden() {
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({
+ StatusBarNotifChips.FLAG_NAME,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void hasSecondaryOngoingActivity_butNotifsFlagOff_secondaryChipHidden() {
resumeAndGetFragment();
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -672,10 +707,10 @@
assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void hasSecondaryOngoingActivity_flagOn_secondaryChipShownAndNotificationIconsHidden() {
+ @Test
+ @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void hasSecondaryOngoingActivity_flagOn_secondaryChipShownAndNotificationIconsHidden() {
resumeAndGetFragment();
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -687,10 +722,14 @@
assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
- @Test
- @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
- public void hasOngoingActivityButNotificationIconsDisabled_chipHidden_notifsFlagOff() {
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({
+ StatusBarNotifChips.FLAG_NAME,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void hasOngoingActivityButNotificationIconsDisabled_chipHidden_notifsFlagOff() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -704,10 +743,10 @@
assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void hasOngoingActivitiesButNotificationIconsDisabled_chipsHidden_notifsFlagOn() {
+ @Test
+ @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void hasOngoingActivitiesButNotificationIconsDisabled_chipsHidden_notifsFlagOn() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -722,10 +761,14 @@
assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
- public void hasOngoingActivityButAlsoHun_chipHidden_notifsFlagOff() {
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({
+ StatusBarNotifChips.FLAG_NAME,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void hasOngoingActivityButAlsoHun_chipHidden_notifsFlagOff() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -739,10 +782,10 @@
assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void hasOngoingActivitiesButAlsoHun_chipsHidden_notifsFlagOn() {
+ @Test
+ @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void hasOngoingActivitiesButAlsoHun_chipsHidden_notifsFlagOn() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -757,10 +800,14 @@
assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
- public void primaryOngoingActivityEnded_chipHidden_notifsFlagOff() {
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({
+ StatusBarNotifChips.FLAG_NAME,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void primaryOngoingActivityEnded_chipHidden_notifsFlagOff() {
resumeAndGetFragment();
// Ongoing activity started
@@ -780,10 +827,10 @@
assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void primaryOngoingActivityEnded_chipHidden_notifsFlagOn() {
+ @Test
+ @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void primaryOngoingActivityEnded_chipHidden_notifsFlagOn() {
resumeAndGetFragment();
// Ongoing activity started
@@ -803,10 +850,10 @@
assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void secondaryOngoingActivityEnded_chipHidden() {
+ @Test
+ @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void secondaryOngoingActivityEnded_chipHidden() {
resumeAndGetFragment();
// Secondary ongoing activity started
@@ -826,10 +873,14 @@
assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
- public void hasOngoingActivity_hidesNotifsWithoutAnimation_notifsFlagOff() {
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({
+ StatusBarNotifChips.FLAG_NAME,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void hasOngoingActivity_hidesNotifsWithoutAnimation_notifsFlagOff() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// Enable animations for testing so that we can verify we still aren't animating
fragment.enableAnimationsForTesting();
@@ -845,10 +896,10 @@
assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
- @Test
- @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void hasOngoingActivity_hidesNotifsWithoutAnimation_notifsFlagOn() {
+ @Test
+ @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void hasOngoingActivity_hidesNotifsWithoutAnimation_notifsFlagOn() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// Enable animations for testing so that we can verify we still aren't animating
fragment.enableAnimationsForTesting();
@@ -864,10 +915,14 @@
assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
- @Test
- @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
- @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
- public void screenSharingChipsEnabled_ignoresOngoingCallController_notifsFlagOff() {
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ @DisableFlags({
+ StatusBarNotifChips.FLAG_NAME,
+ StatusBarRootModernization.FLAG_NAME,
+ StatusBarChipsModernization.FLAG_NAME
+ })
+ public void screenSharingChipsEnabled_ignoresOngoingCallController_notifsFlagOff() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// WHEN there *is* an ongoing call via old callback
@@ -897,10 +952,10 @@
assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void screenSharingChipsEnabled_ignoresOngoingCallController_notifsFlagOn() {
+ @Test
+ @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void screenSharingChipsEnabled_ignoresOngoingCallController_notifsFlagOn() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// WHEN there *is* an ongoing call via old callback
@@ -931,10 +986,10 @@
assertEquals(View.VISIBLE, getSecondaryOngoingActivityChipView().getVisibility());
}
- @Test
- @EnableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void isHomeStatusBarAllowedByScene_false_everythingHidden() {
+ @Test
+ @EnableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void isHomeStatusBarAllowedByScene_false_everythingHidden() {
resumeAndGetFragment();
mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(false);
@@ -945,10 +1000,10 @@
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
- @Test
- @EnableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void isHomeStatusBarAllowedByScene_true_everythingShown() {
+ @Test
+ @EnableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void isHomeStatusBarAllowedByScene_true_everythingShown() {
resumeAndGetFragment();
mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(true);
@@ -959,10 +1014,10 @@
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
- @Test
- @EnableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_isHomeStatusBarAllowedBySceneFalse_disableValuesIgnored() {
+ @Test
+ @EnableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_isHomeStatusBarAllowedBySceneFalse_disableValuesIgnored() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// WHEN the scene doesn't allow the status bar
@@ -977,10 +1032,10 @@
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
- @Test
- @EnableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_isHomeStatusBarAllowedBySceneTrue_disableValuesUsed() {
+ @Test
+ @EnableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_isHomeStatusBarAllowedBySceneTrue_disableValuesUsed() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// WHEN the scene does allow the status bar
@@ -995,10 +1050,10 @@
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
- @Test
- @DisableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void isHomeStatusBarAllowedByScene_sceneContainerDisabled_valueNotUsed() {
+ @Test
+ @DisableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void isHomeStatusBarAllowedByScene_sceneContainerDisabled_valueNotUsed() {
resumeAndGetFragment();
// Even if the scene says to hide the home status bar
@@ -1010,9 +1065,9 @@
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_isDozing_clockAndSystemInfoVisible() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_isDozing_clockAndSystemInfoVisible() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mStatusBarStateController.isDozing()).thenReturn(true);
@@ -1022,9 +1077,9 @@
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_NotDozing_clockAndSystemInfoVisible() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_NotDozing_clockAndSystemInfoVisible() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mStatusBarStateController.isDozing()).thenReturn(false);
@@ -1034,9 +1089,9 @@
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_headsUpShouldBeVisibleTrue_clockDisabled() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_headsUpShouldBeVisibleTrue_clockDisabled() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(true);
@@ -1045,9 +1100,9 @@
assertEquals(View.GONE, getClockView().getVisibility());
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void disable_headsUpShouldBeVisibleFalse_clockNotDisabled() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void disable_headsUpShouldBeVisibleFalse_clockNotDisabled() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(false);
@@ -1098,10 +1153,10 @@
assertFalse(contains);
}
- @Test
- @DisableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void testStatusBarIcons_hiddenThroughoutCameraLaunch() {
+ @Test
+ @DisableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void testStatusBarIcons_hiddenThroughoutCameraLaunch() {
final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
mockSecureCameraLaunch(fragment, true /* launched */);
@@ -1121,10 +1176,10 @@
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
- @Test
- @DisableSceneContainer
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void testStatusBarIcons_hiddenThroughoutLockscreenToDreamTransition() {
+ @Test
+ @DisableSceneContainer
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void testStatusBarIcons_hiddenThroughoutLockscreenToDreamTransition() {
final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// WHEN a transition to dream has started
@@ -1158,9 +1213,9 @@
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
- @Test
- @DisableFlags(StatusBarRootModernization.FLAG_NAME)
- public void testStatusBarIcons_lockscreenToDreamTransitionButNotDreaming_iconsVisible() {
+ @Test
+ @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+ public void testStatusBarIcons_lockscreenToDreamTransitionButNotDreaming_iconsVisible() {
final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
// WHEN a transition to dream has started but we're *not* dreaming
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
index 2bff0c6..1828da5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
@@ -160,6 +160,7 @@
val Kosmos.shortcutHelperViewModel by
Kosmos.Fixture {
ShortcutHelperViewModel(
+ applicationContext,
mockRoleManager,
userTracker,
applicationCoroutineScope,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorKosmos.kt
index fcd14d8..d8d4d2b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorKosmos.kt
@@ -20,12 +20,14 @@
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.statusbar.chips.statusBarChipsLogger
import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
+import com.android.systemui.statusbar.phone.ongoingcall.domain.interactor.ongoingCallInteractor
val Kosmos.callChipInteractor: CallChipInteractor by
Kosmos.Fixture {
CallChipInteractor(
scope = applicationCoroutineScope,
repository = ongoingCallRepository,
+ ongoingCallInteractor = ongoingCallInteractor,
logger = statusBarChipsLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt
new file mode 100644
index 0000000..51fb36f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.ongoingcall.domain.interactor
+
+import com.android.systemui.activity.data.repository.activityManagerRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+
+val Kosmos.ongoingCallInteractor: OngoingCallInteractor by
+ Kosmos.Fixture {
+ OngoingCallInteractor(
+ scope = applicationCoroutineScope,
+ activeNotificationsInteractor = activeNotificationsInteractor,
+ activityManagerRepository = activityManagerRepository,
+ logBuffer = logcatLogBuffer("OngoingCallInteractorKosmos"),
+ )
+ }
diff --git a/packages/Vcn/service-b/Android.bp b/packages/Vcn/service-b/Android.bp
index 26d8397..c1a1ee7 100644
--- a/packages/Vcn/service-b/Android.bp
+++ b/packages/Vcn/service-b/Android.bp
@@ -77,6 +77,7 @@
"framework-connectivity-t-pre-jarjar",
"framework-connectivity-b-pre-jarjar",
"framework-wifi.stubs.module_lib",
+ "keepanno-annotations",
"modules-utils-statemachine",
"unsupportedappusage",
],
diff --git a/packages/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java b/packages/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java
new file mode 100644
index 0000000..02c8ce4
--- /dev/null
+++ b/packages/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.tools.r8.keepanno.annotations.KeepItemKind;
+import com.android.tools.r8.keepanno.annotations.UsedByReflection;
+
+/**
+ * Service initializer for VCN. This is called by system server to create a new instance of
+ * VcnManagementService.
+ */
+// This class is reflectively invoked from SystemServer and ConnectivityServiceInitializer.
+// Without this annotation, this class will be treated as unused class and be removed during build
+// time.
+@UsedByReflection(kind = KeepItemKind.CLASS_AND_METHODS)
+public final class ConnectivityServiceInitializerB extends SystemService {
+ private static final String TAG = ConnectivityServiceInitializerB.class.getSimpleName();
+ private final VcnManagementService mVcnManagementService;
+
+ public ConnectivityServiceInitializerB(Context context) {
+ super(context);
+ mVcnManagementService = VcnManagementService.create(context);
+ }
+
+ @Override
+ public void onStart() {
+ if (mVcnManagementService != null) {
+ Log.i(TAG, "Registering " + Context.VCN_MANAGEMENT_SERVICE);
+ publishBinderService(
+ Context.VCN_MANAGEMENT_SERVICE,
+ mVcnManagementService,
+ /* allowIsolated= */ false);
+ }
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (mVcnManagementService != null && phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ Log.i(TAG, "Starting " + Context.VCN_MANAGEMENT_SERVICE);
+ mVcnManagementService.systemReady();
+ }
+ }
+}
diff --git a/services/Android.bp b/services/Android.bp
index 225304f..fc0bb33 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -294,10 +294,6 @@
"service-permission.stubs.system_server",
"service-rkp.stubs.system_server",
"service-sdksandbox.stubs.system_server",
-
- // TODO: b/30242953 This is for accessing IVcnManagementService and
- // can be removed VCN is in mainline
- "framework-connectivity-b-pre-jarjar",
],
soong_config_variables: {
diff --git a/services/autofill/features.aconfig b/services/autofill/features.aconfig
index 80e0e5d..b78d103 100644
--- a/services/autofill/features.aconfig
+++ b/services/autofill/features.aconfig
@@ -2,6 +2,13 @@
container: "system"
flag {
+ name: "autofill_session_destroyed"
+ namespace: "autofill"
+ description: "Guards against new metrics definitions introduced in W"
+ bug: "342676602"
+}
+
+flag {
name: "autofill_w_metrics"
namespace: "autofill"
description: "Guards against new metrics definitions introduced in W"
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index cd4ace2..5cf96bf 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -61,6 +61,7 @@
import android.service.autofill.FillEventHistory.Event;
import android.service.autofill.FillEventHistory.Event.NoSaveReason;
import android.service.autofill.FillResponse;
+import android.service.autofill.Flags;
import android.service.autofill.IAutoFillService;
import android.service.autofill.InlineSuggestionRenderService;
import android.service.autofill.SaveInfo;
@@ -100,6 +101,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Random;
+
/**
* Bridge between the {@code system_server}'s {@link AutofillManagerService} and the
* app's {@link IAutoFillService} implementation.
@@ -748,6 +750,22 @@
@GuardedBy("mLock")
void removeSessionLocked(int sessionId) {
mSessions.remove(sessionId);
+ if (Flags.autofillSessionDestroyed()) {
+ if (sVerbose) {
+ Slog.v(
+ TAG,
+ "removeSessionLocked(): removed " + sessionId);
+ }
+ RemoteFillService remoteService =
+ new RemoteFillService(
+ getContext(),
+ mInfo.getServiceInfo().getComponentName(),
+ mUserId,
+ /* callbacks= */ null,
+ mMaster.isInstantServiceAllowed(),
+ /* credentialAutofillService= */ null);
+ remoteService.onSessionDestroyed(null);
+ }
}
/**
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 07f5dcc..f1e8884 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -34,6 +34,7 @@
import android.service.autofill.AutofillService;
import android.service.autofill.ConvertCredentialRequest;
import android.service.autofill.ConvertCredentialResponse;
+import android.service.autofill.FillEventHistory;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
import android.service.autofill.IAutoFillService;
@@ -497,6 +498,14 @@
}));
}
+ public void onSessionDestroyed(@Nullable FillEventHistory history) {
+ boolean success = run(service -> {
+ service.onSessionDestroyed(history);
+ });
+
+ if (sVerbose) Slog.v(TAG, "called onSessionDestroyed(): " + success);
+ }
+
void onSavedPasswordCountRequest(IResultReceiver receiver) {
run(service -> service.onSavedPasswordCountRequest(receiver));
}
diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java
index fb527c1..2412b01 100644
--- a/services/core/java/com/android/server/DockObserver.java
+++ b/services/core/java/com/android/server/DockObserver.java
@@ -19,6 +19,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.media.AudioManager;
import android.media.Ringtone;
@@ -35,6 +36,7 @@
import android.util.Pair;
import android.util.Slog;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -259,11 +261,19 @@
+ mReportedDockState);
final int previousDockState = mPreviousDockState;
mPreviousDockState = mReportedDockState;
- // Skip the dock intent if not yet provisioned.
+
final ContentResolver cr = getContext().getContentResolver();
- if (!mDeviceProvisionedObserver.isDeviceProvisioned()) {
- Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
- return;
+
+ /// If the allow dock rotation before provision is enabled then we allow rotation.
+ final Resources r = getContext().getResources();
+ final boolean allowDockBeforeProvision =
+ r.getBoolean(R.bool.config_allowDockBeforeProvision);
+ if (!allowDockBeforeProvision) {
+ // Skip the dock intent if not yet provisioned.
+ if (!mDeviceProvisionedObserver.isDeviceProvisioned()) {
+ Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
+ return;
+ }
}
// Pack up the values and broadcast them to everyone
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index d13dd2f..896c9b8 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -885,8 +885,6 @@
? customModeType
: MODE_NIGHT_CUSTOM_TYPE_UNKNOWN;
mNightMode.set(mode);
- //deactivates AttentionMode if user toggles DarkTheme
- mAttentionModeThemeOverlay = MODE_ATTENTION_THEME_OVERLAY_OFF;
resetNightModeOverrideLocked();
persistNightMode(user);
// on screen off will update configuration instead
@@ -1009,15 +1007,16 @@
@Override
public boolean setNightModeActivatedForCustomMode(int modeNightCustomType, boolean active) {
- return setNightModeActivatedForModeInternal(modeNightCustomType, active);
+ return setNightModeActivatedForModeInternal(modeNightCustomType, active, false);
}
@Override
public boolean setNightModeActivated(boolean active) {
- return setNightModeActivatedForModeInternal(mNightModeCustomType, active);
+ return setNightModeActivatedForModeInternal(mNightModeCustomType, active, true);
}
- private boolean setNightModeActivatedForModeInternal(int modeCustomType, boolean active) {
+ private boolean setNightModeActivatedForModeInternal(int modeCustomType,
+ boolean active, boolean isUserInteraction) {
if (getContext().checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
!= PackageManager.PERMISSION_GRANTED) {
@@ -1053,13 +1052,16 @@
mOverrideNightModeOn = active;
mOverrideNightModeUser = mCurrentUser;
persistNightModeOverrides(mCurrentUser);
- } else if (mNightMode.get() == UiModeManager.MODE_NIGHT_NO
- && active) {
+ } else if (mNightMode.get() == UiModeManager.MODE_NIGHT_NO && active) {
mNightMode.set(UiModeManager.MODE_NIGHT_YES);
- } else if (mNightMode.get() == UiModeManager.MODE_NIGHT_YES
- && !active) {
+ } else if (mNightMode.get() == UiModeManager.MODE_NIGHT_YES && !active) {
mNightMode.set(UiModeManager.MODE_NIGHT_NO);
}
+
+ if (isUserInteraction) {
+ // deactivates AttentionMode if user toggles DarkTheme
+ mAttentionModeThemeOverlay = MODE_ATTENTION_THEME_OVERLAY_OFF;
+ }
updateConfigurationLocked();
applyConfigurationExternallyLocked();
persistNightMode(mCurrentUser);
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 06c586f..295e044 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3191,7 +3191,7 @@
resolveProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId,
Process.INVALID_UID, null, null,
Context.DEVICE_ID_DEFAULT, proxyFlags, !isProxyTrusted,
- "proxy " + message, shouldCollectMessage);
+ "proxy " + message, shouldCollectMessage, 1);
if (proxyReturn.getOpMode() != AppOpsManager.MODE_ALLOWED) {
return new SyncNotedAppOp(proxyReturn.getOpMode(), code, proxiedAttributionTag,
proxiedPackageName);
@@ -3210,7 +3210,20 @@
return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
proxiedAttributionTag, proxiedVirtualDeviceId, proxyUid, resolveProxyPackageName,
proxyAttributionTag, proxyVirtualDeviceId, proxiedFlags, shouldCollectAsyncNotedOp,
- message, shouldCollectMessage);
+ message, shouldCollectMessage, 1);
+ }
+
+ @Override
+ public void noteOperationsInBatch(Map batchedNoteOps) {
+ for (var entry : ((Map<AppOpsManager.NotedOp, Integer>) batchedNoteOps).entrySet()) {
+ AppOpsManager.NotedOp notedOp = entry.getKey();
+ int notedCount = entry.getValue();
+ mCheckOpsDelegateDispatcher.noteOperation(
+ notedOp.getOp(), notedOp.getUid(), notedOp.getPackageName(),
+ notedOp.getAttributionTag(), notedOp.getVirtualDeviceId(),
+ notedOp.getShouldCollectAsyncNotedOp(), notedOp.getMessage(),
+ notedOp.getShouldCollectMessage(), notedCount);
+ }
}
@Override
@@ -3228,7 +3241,7 @@
}
return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
attributionTag, Context.DEVICE_ID_DEFAULT, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage);
+ shouldCollectMessage, 1);
}
@Override
@@ -3237,13 +3250,12 @@
String message, boolean shouldCollectMessage) {
return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage);
+ shouldCollectMessage, 1);
}
private SyncNotedAppOp noteOperationImpl(int code, int uid, @Nullable String packageName,
- @Nullable String attributionTag, int virtualDeviceId,
- boolean shouldCollectAsyncNotedOp, @Nullable String message,
- boolean shouldCollectMessage) {
+ @Nullable String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
+ @Nullable String message, boolean shouldCollectMessage, int notedCount) {
String resolvedPackageName;
if (!shouldUseNewCheckOp()) {
verifyIncomingUid(uid);
@@ -3278,14 +3290,14 @@
return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
virtualDeviceId, Process.INVALID_UID, null, null,
Context.DEVICE_ID_DEFAULT, AppOpsManager.OP_FLAG_SELF, shouldCollectAsyncNotedOp,
- message, shouldCollectMessage);
+ message, shouldCollectMessage, notedCount);
}
private SyncNotedAppOp noteOperationUnchecked(int code, int uid, @NonNull String packageName,
@Nullable String attributionTag, int virtualDeviceId, int proxyUid,
String proxyPackageName, @Nullable String proxyAttributionTag, int proxyVirtualDeviceId,
@OpFlags int flags, boolean shouldCollectAsyncNotedOp, @Nullable String message,
- boolean shouldCollectMessage) {
+ boolean shouldCollectMessage, int notedCount) {
PackageVerificationResult pvr;
try {
pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
@@ -3388,11 +3400,11 @@
virtualDeviceId, flags, AppOpsManager.MODE_ALLOWED);
attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag,
- getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags);
+ getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags, notedCount);
if (shouldCollectAsyncNotedOp) {
collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message,
- shouldCollectMessage);
+ shouldCollectMessage, notedCount);
}
return new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, code, attributionTag,
@@ -3551,7 +3563,7 @@
*/
private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
@Nullable String attributionTag, @OpFlags int flags, @NonNull String message,
- boolean shouldCollectMessage) {
+ boolean shouldCollectMessage, int notedCount) {
Objects.requireNonNull(message);
int callingUid = Binder.getCallingUid();
@@ -3559,42 +3571,51 @@
final long token = Binder.clearCallingIdentity();
try {
synchronized (this) {
- Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
-
- RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
- AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
- attributionTag, message, System.currentTimeMillis());
- final boolean[] wasNoteForwarded = {false};
-
if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) != 0
&& shouldCollectMessage) {
reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode,
attributionTag, message);
}
- if (callbacks != null) {
+ Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
+ RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
+ if (callbacks == null) {
+ return;
+ }
+
+ final boolean[] wasNoteForwarded = {false};
+ if (Flags.rateLimitBatchedNoteOpAsyncCallbacksEnabled()) {
+ notedCount = 1;
+ }
+
+ for (int i = 0; i < notedCount; i++) {
+ AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
+ attributionTag, message, System.currentTimeMillis());
+ wasNoteForwarded[0] = false;
callbacks.broadcast((cb) -> {
try {
cb.opNoted(asyncNotedOp);
wasNoteForwarded[0] = true;
} catch (RemoteException e) {
Slog.e(TAG,
- "Could not forward noteOp of " + opCode + " to " + packageName
+ "Could not forward noteOp of " + opCode + " to "
+ + packageName
+ "/" + uid + "(" + attributionTag + ")", e);
}
});
- }
- if (!wasNoteForwarded[0]) {
- ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key);
- if (unforwardedOps == null) {
- unforwardedOps = new ArrayList<>(1);
- mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
- }
+ if (!wasNoteForwarded[0]) {
+ ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(
+ key);
+ if (unforwardedOps == null) {
+ unforwardedOps = new ArrayList<>(1);
+ mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
+ }
- unforwardedOps.add(asyncNotedOp);
- if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) {
- unforwardedOps.remove(0);
+ unforwardedOps.add(asyncNotedOp);
+ if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) {
+ unforwardedOps.remove(0);
+ }
}
}
}
@@ -4026,7 +4047,7 @@
if (shouldCollectAsyncNotedOp && !isRestricted) {
collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF,
- message, shouldCollectMessage);
+ message, shouldCollectMessage, 1);
}
return new SyncNotedAppOp(isRestricted ? MODE_IGNORED : MODE_ALLOWED, code, attributionTag,
@@ -7574,34 +7595,36 @@
public SyncNotedAppOp noteOperation(int code, int uid, String packageName,
String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
- String message, boolean shouldCollectMessage) {
+ String message, boolean shouldCollectMessage, int notedCount) {
if (mPolicy != null) {
if (mCheckOpsDelegate != null) {
return mPolicy.noteOperation(code, uid, packageName, attributionTag,
virtualDeviceId, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage, this::noteDelegateOperationImpl
+ shouldCollectMessage, notedCount, this::noteDelegateOperationImpl
);
} else {
return mPolicy.noteOperation(code, uid, packageName, attributionTag,
virtualDeviceId, shouldCollectAsyncNotedOp, message,
- shouldCollectMessage, AppOpsService.this::noteOperationImpl
+ shouldCollectMessage, notedCount, AppOpsService.this::noteOperationImpl
);
}
} else if (mCheckOpsDelegate != null) {
return noteDelegateOperationImpl(code, uid, packageName, attributionTag,
- virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ notedCount);
}
return noteOperationImpl(code, uid, packageName, attributionTag,
- virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ notedCount);
}
private SyncNotedAppOp noteDelegateOperationImpl(int code, int uid,
@Nullable String packageName, @Nullable String featureId, int virtualDeviceId,
boolean shouldCollectAsyncNotedOp, @Nullable String message,
- boolean shouldCollectMessage) {
+ boolean shouldCollectMessage, int notedCount) {
return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId,
virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
- AppOpsService.this::noteOperationImpl
+ notedCount, AppOpsService.this::noteOperationImpl
);
}
diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java
index 314664b..4d114b4 100644
--- a/services/core/java/com/android/server/appop/AttributedOp.java
+++ b/services/core/java/com/android/server/appop/AttributedOp.java
@@ -100,10 +100,12 @@
* @param proxyDeviceId The device Id of the proxy
* @param uidState UID state of the app noteOp/startOp was called for
* @param flags OpFlags of the call
+ * @param accessCount The number of times the op is accessed
*/
public void accessed(int proxyUid, @Nullable String proxyPackageName,
@Nullable String proxyAttributionTag, @Nullable String proxyDeviceId,
- @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags) {
+ @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags,
+ int accessCount) {
long accessTime = System.currentTimeMillis();
accessed(accessTime, -1, proxyUid, proxyPackageName, proxyAttributionTag, proxyDeviceId,
uidState, flags);
@@ -111,7 +113,7 @@
mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
parent.packageName, persistentDeviceId, tag, uidState, flags, accessTime,
AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE,
- DiscreteRegistry.ACCESS_TYPE_NOTE_OP);
+ DiscreteRegistry.ACCESS_TYPE_NOTE_OP, accessCount);
}
/**
@@ -255,7 +257,7 @@
if (isStarted) {
mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
parent.packageName, persistentDeviceId, tag, uidState, flags, startTime,
- attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP);
+ attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP, 1);
}
}
@@ -451,7 +453,7 @@
mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
parent.packageName, persistentDeviceId, tag, event.getUidState(),
event.getFlags(), startTime, event.getAttributionFlags(),
- event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP);
+ event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP, 1);
if (shouldSendActive) {
mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
parent.packageName, tag, event.getVirtualDeviceId(), true,
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 6b02538..5e67f26 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -475,7 +475,7 @@
@NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState,
@OpFlags int flags, long accessTime,
@AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
- @DiscreteRegistry.AccessType int accessType) {
+ @DiscreteRegistry.AccessType int accessType, int accessCount) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
if (!isPersistenceInitializedMLocked()) {
@@ -484,7 +484,7 @@
}
getUpdatedPendingHistoricalOpsMLocked(
System.currentTimeMillis()).increaseAccessCount(op, uid, packageName,
- attributionTag, uidState, flags, 1);
+ attributionTag, uidState, flags, accessCount);
mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op,
attributionTag, flags, uidState, accessTime, -1, attributionFlags,
diff --git a/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java b/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
index 4736918..7502664 100644
--- a/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
+++ b/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
@@ -27,6 +27,7 @@
import static android.Manifest.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION;
import static android.Manifest.permission.MODIFY_AUDIO_ROUTING;
import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS;
+import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED;
import static android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS;
import static android.Manifest.permission.MODIFY_PHONE_STATE;
import static android.Manifest.permission.RECORD_AUDIO;
@@ -84,6 +85,8 @@
MONITORED_PERMS[PermissionEnum.BLUETOOTH_CONNECT] = BLUETOOTH_CONNECT;
MONITORED_PERMS[PermissionEnum.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION] =
BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION;
+ MONITORED_PERMS[PermissionEnum.MODIFY_AUDIO_SETTINGS_PRIVILEGED] =
+ MODIFY_AUDIO_SETTINGS_PRIVILEGED;
}
private final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
index e9cb279..e989d68 100644
--- a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
+++ b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
@@ -40,7 +40,7 @@
import com.android.internal.util.function.DodecFunction;
import com.android.internal.util.function.HexConsumer;
import com.android.internal.util.function.HexFunction;
-import com.android.internal.util.function.OctFunction;
+import com.android.internal.util.function.NonaFunction;
import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.TriFunction;
import com.android.internal.util.function.UndecFunction;
@@ -351,22 +351,22 @@
@Override
public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
@Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
- @Nullable String message, boolean shouldCollectMessage,
- @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String,
- Boolean, SyncNotedAppOp> superImpl) {
+ @Nullable String message, boolean shouldCollectMessage, int notedCount,
+ @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String,
+ Boolean, Integer, SyncNotedAppOp> superImpl) {
if (uid == mDelegateAndOwnerUid && isDelegateOp(code)) {
final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid),
Process.SHELL_UID);
final long identity = Binder.clearCallingIdentity();
try {
return superImpl.apply(code, shellUid, SHELL_PKG, featureId, virtualDeviceId,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
return superImpl.apply(code, uid, packageName, featureId, virtualDeviceId,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount);
}
@Override
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index ecffd38..33210e2 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -53,7 +53,7 @@
import com.android.internal.util.function.DodecFunction;
import com.android.internal.util.function.HexConsumer;
import com.android.internal.util.function.HexFunction;
-import com.android.internal.util.function.OctFunction;
+import com.android.internal.util.function.NonaFunction;
import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.UndecFunction;
import com.android.server.LocalServices;
@@ -246,11 +246,12 @@
public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
@Nullable String attributionTag, int virtualDeviceId,
boolean shouldCollectAsyncNotedOp, @Nullable String message,
- boolean shouldCollectMessage, @NonNull OctFunction<Integer, Integer, String, String,
- Integer, Boolean, String, Boolean, SyncNotedAppOp> superImpl) {
+ boolean shouldCollectMessage, int notedCount,
+ @NonNull NonaFunction<Integer, Integer, String, String,
+ Integer, Boolean, String, Boolean, Integer, SyncNotedAppOp> superImpl) {
return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag),
resolveUid(code, uid), packageName, attributionTag, virtualDeviceId,
- shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount);
}
@Override
diff --git a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
index 15c3099..1b6ce9d 100644
--- a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
+++ b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
@@ -119,6 +119,7 @@
@Override
public void finishSession() {
+ Slog.d(TAG, "Session finish requested, ending vibration session...");
// Do not abort session in HAL, wait for ongoing vibration requests to complete.
// This might take a while to end the session, but it can be aborted by cancelSession.
requestEndSession(Status.FINISHED, /* shouldAbort= */ false, /* isVendorRequest= */ true);
@@ -126,6 +127,7 @@
@Override
public void cancelSession() {
+ Slog.d(TAG, "Session cancel requested, aborting vibration session...");
// Always abort session in HAL while cancelling it.
// This might be triggered after finishSession was already called.
requestEndSession(Status.CANCELLED_BY_USER, /* shouldAbort= */ true,
@@ -228,13 +230,14 @@
@Override
public void notifySessionCallback() {
synchronized (mLock) {
+ Slog.d(TAG, "Session callback received, ending vibration session...");
// If end was not requested then the HAL has cancelled the session.
maybeSetEndRequestLocked(Status.CANCELLED_BY_UNKNOWN_REASON,
/* isVendorRequest= */ false);
maybeSetStatusToRequestedLocked();
clearVibrationConductor();
+ mHandler.post(() -> mManagerHooks.onSessionReleased(mSessionId));
}
- mHandler.post(() -> mManagerHooks.onSessionReleased(mSessionId));
}
@Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index fde6ce2..aa63c4a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -429,6 +429,8 @@
"/apex/com.android.tethering/javalib/service-connectivity.jar";
private static final String CONNECTIVITY_SERVICE_INITIALIZER_CLASS =
"com.android.server.ConnectivityServiceInitializer";
+ private static final String CONNECTIVITY_SERVICE_INITIALIZER_B_CLASS =
+ "com.android.server.ConnectivityServiceInitializerB";
private static final String NETWORK_STATS_SERVICE_INITIALIZER_CLASS =
"com.android.server.NetworkStatsServiceInitializer";
private static final String UWB_APEX_SERVICE_JAR_PATH =
@@ -1486,7 +1488,6 @@
IStorageManager storageManager = null;
NetworkManagementService networkManagement = null;
VpnManagerService vpnManager = null;
- VcnManagementService vcnManagement = null;
NetworkPolicyManagerService networkPolicy = null;
WindowManagerService wm = null;
NetworkTimeUpdateService networkTimeUpdater = null;
@@ -2232,8 +2233,10 @@
t.traceBegin("StartVcnManagementService");
try {
- vcnManagement = VcnManagementService.create(context);
- ServiceManager.addService(Context.VCN_MANAGEMENT_SERVICE, vcnManagement);
+ // TODO: b/375213246 When VCN is in mainline module, load it from the apex path.
+ // Whether VCN will be in apex or in the platform will be gated by a build system
+ // flag.
+ mSystemServiceManager.startService(CONNECTIVITY_SERVICE_INITIALIZER_B_CLASS);
} catch (Throwable e) {
reportWtf("starting VCN Management Service", e);
}
@@ -3159,7 +3162,6 @@
final MediaRouterService mediaRouterF = mediaRouter;
final MmsServiceBroker mmsServiceF = mmsService;
final VpnManagerService vpnManagerF = vpnManager;
- final VcnManagementService vcnManagementF = vcnManagement;
final WindowManagerService windowManagerF = wm;
final ConnectivityManager connectivityF = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -3286,15 +3288,6 @@
reportWtf("making VpnManagerService ready", e);
}
t.traceEnd();
- t.traceBegin("MakeVcnManagementServiceReady");
- try {
- if (vcnManagementF != null) {
- vcnManagementF.systemReady();
- }
- } catch (Throwable e) {
- reportWtf("making VcnManagementService ready", e);
- }
- t.traceEnd();
t.traceBegin("MakeNetworkPolicyServiceReady");
try {
if (networkPolicyF != null) {
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index 3b0cb4a..0404b82 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -1460,9 +1460,12 @@
verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
}
- private void testAttentionModeThemeOverlay(boolean modeNight) throws RemoteException {
+ // Test the attention mode overlay with all the possible attention modes and the initial night
+ // mode state. Also tests if the attention mode is turned off when the night mode is toggled by
+ // the user.
+ private void testAttentionModeThemeOverlay(boolean initialNightMode) throws RemoteException {
//setup
- if (modeNight) {
+ if (initialNightMode) {
mService.setNightMode(MODE_NIGHT_YES);
assertTrue(mUiManagerService.getConfiguration().isNightModeActive());
} else {
@@ -1472,21 +1475,29 @@
// attention modes with expected night modes
Map<Integer, Boolean> modes = Map.of(
- MODE_ATTENTION_THEME_OVERLAY_OFF, modeNight,
+ MODE_ATTENTION_THEME_OVERLAY_OFF, initialNightMode,
MODE_ATTENTION_THEME_OVERLAY_DAY, false,
MODE_ATTENTION_THEME_OVERLAY_NIGHT, true
);
// test
- for (int aMode : modes.keySet()) {
+ for (int attentionMode : modes.keySet()) {
try {
- mService.setAttentionModeThemeOverlay(aMode);
+ mService.setAttentionModeThemeOverlay(attentionMode);
int appliedAMode = mService.getAttentionModeThemeOverlay();
- boolean nMode = modes.get(aMode);
+ boolean expectedNightMode = modes.get(attentionMode);
- assertEquals(aMode, appliedAMode);
- assertEquals(isNightModeActivated(), nMode);
+ assertEquals(attentionMode, appliedAMode);
+ assertEquals(expectedNightMode, isNightModeActivated());
+
+ // If attentionMode is active, flip the night mode and assets
+ // the attention mode is disabled
+ if (attentionMode != MODE_ATTENTION_THEME_OVERLAY_OFF) {
+ mService.setNightModeActivated(!expectedNightMode);
+ assertEquals(MODE_ATTENTION_THEME_OVERLAY_OFF,
+ mService.getAttentionModeThemeOverlay());
+ }
} catch (RemoteException e) {
fail("Error communicating with server: " + e.getMessage());
}