Merge "Add permission access to DPM certificate mng APIs"
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index c5510b7..6a7904c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -3744,7 +3744,7 @@
// Enforce that only the app itself (or shared uid participant) can schedule a
// job that runs one of the app's services, as well as verifying that the
// named service properly requires the BIND_JOB_SERVICE permission
- private void enforceValidJobRequest(int uid, JobInfo job) {
+ private void enforceValidJobRequest(int uid, int pid, JobInfo job) {
final PackageManager pm = getContext()
.createContextAsUser(UserHandle.getUserHandleForUid(uid), 0)
.getPackageManager();
@@ -3768,6 +3768,10 @@
throw new IllegalArgumentException(
"Tried to schedule job for non-existent component: " + service);
}
+ if (job.isPersisted() && !canPersistJobs(pid, uid)) {
+ throw new IllegalArgumentException("Requested job cannot be persisted without"
+ + " holding android.permission.RECEIVE_BOOT_COMPLETED permission");
+ }
}
private boolean canPersistJobs(int pid, int uid) {
@@ -3915,13 +3919,7 @@
final int uid = Binder.getCallingUid();
final int userId = UserHandle.getUserId(uid);
- enforceValidJobRequest(uid, job);
- if (job.isPersisted()) {
- if (!canPersistJobs(pid, uid)) {
- throw new IllegalArgumentException("Error: requested job be persisted without"
- + " holding RECEIVE_BOOT_COMPLETED permission.");
- }
- }
+ enforceValidJobRequest(uid, pid, job);
final int result = validateJob(job, uid, -1, null, null);
if (result != JobScheduler.RESULT_SUCCESS) {
@@ -3948,9 +3946,10 @@
Slog.d(TAG, "Enqueueing job: " + job.toString() + " work: " + work);
}
final int uid = Binder.getCallingUid();
+ final int pid = Binder.getCallingPid();
final int userId = UserHandle.getUserId(uid);
- enforceValidJobRequest(uid, job);
+ enforceValidJobRequest(uid, pid, job);
if (work == null) {
throw new NullPointerException("work is null");
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index d048cca..ceb47ea 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -107,6 +107,8 @@
private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
/** Amount of time the JobScheduler will wait for a response from an app for a message. */
private static final long OP_TIMEOUT_MILLIS = 8 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
+ /** Amount of time the JobScheduler will wait for a job to provide a required notification. */
+ private static final long NOTIFICATION_TIMEOUT_MILLIS = 10_000L * Build.HW_TIMEOUT_MULTIPLIER;
private static final String[] VERB_STRINGS = {
"VERB_BINDING", "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_FINISHED"
@@ -190,6 +192,8 @@
private long mMinExecutionGuaranteeMillis;
/** The absolute maximum amount of time the job can run */
private long mMaxExecutionTimeMillis;
+ /** Whether this job is required to provide a notification and we're still waiting for it. */
+ private boolean mAwaitingNotification;
private long mEstimatedDownloadBytes;
private long mEstimatedUploadBytes;
@@ -348,6 +352,7 @@
mEstimatedDownloadBytes = job.getEstimatedNetworkDownloadBytes();
mEstimatedUploadBytes = job.getEstimatedNetworkUploadBytes();
mTransferredDownloadBytes = mTransferredUploadBytes = 0;
+ mAwaitingNotification = job.isUserVisibleJob();
final long whenDeferred = job.getWhenStandbyDeferred();
if (whenDeferred > 0) {
@@ -771,6 +776,12 @@
mNotificationCoordinator.enqueueNotification(this, callingPkgName,
callingPid, callingUid, notificationId,
notification, jobEndNotificationPolicy);
+ if (mAwaitingNotification) {
+ mAwaitingNotification = false;
+ if (mVerb == VERB_EXECUTING) {
+ scheduleOpTimeOutLocked();
+ }
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -1183,6 +1194,8 @@
}
final long latestStopTimeElapsed =
mExecutionStartTimeElapsed + mMaxExecutionTimeMillis;
+ final long earliestStopTimeElapsed =
+ mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis;
final long nowElapsed = sElapsedRealtimeClock.millis();
if (nowElapsed >= latestStopTimeElapsed) {
// Not an error - client ran out of time.
@@ -1191,7 +1204,7 @@
mParams.setStopReason(JobParameters.STOP_REASON_TIMEOUT,
JobParameters.INTERNAL_STOP_REASON_TIMEOUT, "client timed out");
sendStopMessageLocked("timeout while executing");
- } else {
+ } else if (nowElapsed >= earliestStopTimeElapsed) {
// We've given the app the minimum execution time. See if we should stop it or
// let it continue running
final String reason = mJobConcurrencyManager.shouldStopRunningJobLocked(this);
@@ -1209,6 +1222,14 @@
+ " continue to run past min execution time");
scheduleOpTimeOutLocked();
}
+ } else if (mAwaitingNotification) {
+ onSlowAppResponseLocked(/* reschedule */ true, /* updateStopReasons */ true,
+ /* debugReason */ "timed out while stopping",
+ /* anrMessage */ "required notification not provided",
+ /* triggerAnr */ true);
+ } else {
+ Slog.e(TAG, "Unexpected op timeout while EXECUTING");
+ scheduleOpTimeOutLocked();
}
break;
default:
@@ -1402,20 +1423,24 @@
private void scheduleOpTimeOutLocked() {
removeOpTimeOutLocked();
- // TODO(260848384): enforce setNotification timeout for user-initiated jobs
final long timeoutMillis;
switch (mVerb) {
case VERB_EXECUTING:
+ long minTimeout;
final long earliestStopTimeElapsed =
mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis;
final long latestStopTimeElapsed =
mExecutionStartTimeElapsed + mMaxExecutionTimeMillis;
final long nowElapsed = sElapsedRealtimeClock.millis();
if (nowElapsed < earliestStopTimeElapsed) {
- timeoutMillis = earliestStopTimeElapsed - nowElapsed;
+ minTimeout = earliestStopTimeElapsed - nowElapsed;
} else {
- timeoutMillis = latestStopTimeElapsed - nowElapsed;
+ minTimeout = latestStopTimeElapsed - nowElapsed;
}
+ if (mAwaitingNotification) {
+ minTimeout = Math.min(minTimeout, NOTIFICATION_TIMEOUT_MILLIS);
+ }
+ timeoutMillis = minTimeout;
break;
case VERB_BINDING:
diff --git a/core/api/current.txt b/core/api/current.txt
index 81322e5..7e03b36 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -2048,16 +2048,16 @@
field public static final int system_primary_container_light;
field public static final int system_primary_dark;
field public static final int system_primary_fixed_dark;
- field public static final int system_primary_fixed_darker_dark;
- field public static final int system_primary_fixed_darker_light;
+ field public static final int system_primary_fixed_dim_dark;
+ field public static final int system_primary_fixed_dim_light;
field public static final int system_primary_fixed_light;
field public static final int system_primary_light;
field public static final int system_secondary_container_dark;
field public static final int system_secondary_container_light;
field public static final int system_secondary_dark;
field public static final int system_secondary_fixed_dark;
- field public static final int system_secondary_fixed_darker_dark;
- field public static final int system_secondary_fixed_darker_light;
+ field public static final int system_secondary_fixed_dim_dark;
+ field public static final int system_secondary_fixed_dim_light;
field public static final int system_secondary_fixed_light;
field public static final int system_secondary_light;
field public static final int system_surface_bright_dark;
@@ -2082,8 +2082,8 @@
field public static final int system_tertiary_container_light;
field public static final int system_tertiary_dark;
field public static final int system_tertiary_fixed_dark;
- field public static final int system_tertiary_fixed_darker_dark;
- field public static final int system_tertiary_fixed_darker_light;
+ field public static final int system_tertiary_fixed_dim_dark;
+ field public static final int system_tertiary_fixed_dim_light;
field public static final int system_tertiary_fixed_light;
field public static final int system_tertiary_light;
field public static final int system_text_hint_inverse_dark;
@@ -10243,7 +10243,6 @@
method @Deprecated public abstract int getWallpaperDesiredMinimumHeight();
method @Deprecated public abstract int getWallpaperDesiredMinimumWidth();
method public abstract void grantUriPermission(String, android.net.Uri, int);
- method public boolean isDeviceContext();
method public abstract boolean isDeviceProtectedStorage();
method public boolean isRestricted();
method public boolean isUiContext();
@@ -15445,8 +15444,9 @@
ctor @Deprecated public EmbossMaskFilter(float[], float, float, float);
}
- public final class Gainmap {
+ public final class Gainmap implements android.os.Parcelable {
ctor public Gainmap(@NonNull android.graphics.Bitmap);
+ method public int describeContents();
method @NonNull public float getDisplayRatioForFullHdr();
method @NonNull public float[] getEpsilonHdr();
method @NonNull public float[] getEpsilonSdr();
@@ -15463,6 +15463,8 @@
method @NonNull public void setMinDisplayRatioForHdrTransition(@FloatRange(from=1.0f) float);
method @NonNull public void setRatioMax(float, float, float);
method @NonNull public void setRatioMin(float, float, float);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.graphics.Gainmap> CREATOR;
}
public class HardwareBufferRenderer implements java.lang.AutoCloseable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 2341971..fc6c1fe 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -463,6 +463,7 @@
field public static final int config_systemAutomotiveCalendarSyncManager = 17039423; // 0x104003f
field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029
+ field public static final int config_systemCallStreaming;
field public static final int config_systemCompanionDeviceProvider = 17039417; // 0x1040039
field public static final int config_systemContacts = 17039403; // 0x104002b
field public static final int config_systemFinancedDeviceController;
@@ -10054,7 +10055,7 @@
public class SharedConnectivityManager {
method public boolean connectKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
method public boolean connectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
- method public boolean disconnectTetherNetwork();
+ method public boolean disconnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
method public boolean forgetKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
method public boolean unregisterCallback(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivityClientCallback);
@@ -10141,7 +10142,7 @@
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onConnectKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
method public abstract void onConnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
- method public abstract void onDisconnectTetherNetwork();
+ method public abstract void onDisconnectTetherNetwork(@NonNull android.net.wifi.sharedconnectivity.app.TetherNetwork);
method public abstract void onForgetKnownNetwork(@NonNull android.net.wifi.sharedconnectivity.app.KnownNetwork);
method public final void setKnownNetworks(@NonNull java.util.List<android.net.wifi.sharedconnectivity.app.KnownNetwork>);
method public final void setSettingsState(@NonNull android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 4e364a2..d5ced04 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -627,6 +627,13 @@
method @NonNull public android.app.admin.ResolutionMechanism<V> getResolutionMechanism();
}
+ public abstract class PolicyUpdateReceiver extends android.content.BroadcastReceiver {
+ field public static final String EXTRA_POLICY_BUNDLE_KEY = "android.app.admin.extra.POLICY_BUNDLE_KEY";
+ field public static final String EXTRA_POLICY_KEY = "android.app.admin.extra.POLICY_KEY";
+ field public static final String EXTRA_POLICY_TARGET_USER_ID = "android.app.admin.extra.POLICY_TARGET_USER_ID";
+ field public static final String EXTRA_POLICY_UPDATE_RESULT_KEY = "android.app.admin.extra.POLICY_UPDATE_RESULT_KEY";
+ }
+
public abstract class ResolutionMechanism<V> implements android.os.Parcelable {
}
@@ -642,6 +649,13 @@
field @NonNull public static final android.app.admin.StringSetUnion STRING_SET_UNION;
}
+ public final class TargetUser {
+ field public static final int GLOBAL_USER_ID = -3; // 0xfffffffd
+ field public static final int LOCAL_USER_ID = -1; // 0xffffffff
+ field public static final int PARENT_USER_ID = -2; // 0xfffffffe
+ field public static final int UNKNOWN_USER_ID = -3; // 0xfffffffd
+ }
+
public final class TopPriority<V> extends android.app.admin.ResolutionMechanism<V> {
method public int describeContents();
method @NonNull public java.util.List<android.app.admin.Authority> getHighestToLowestPriorityAuthorities();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index bed75db..e45944e 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -3068,18 +3068,6 @@
}
@Override
- public boolean isDeviceContext() {
- if (mIsExplicitDeviceId) {
- if (mDeviceId == VirtualDeviceManager.DEVICE_ID_DEFAULT) {
- return true;
- }
- VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class);
- return vdm.isValidVirtualDeviceId(mDeviceId);
- }
- return isAssociatedWithDisplay();
- }
-
- @Override
public void registerDeviceIdChangeListener(@NonNull @CallbackExecutor Executor executor,
@NonNull IntConsumer listener) {
Objects.requireNonNull(executor, "executor cannot be null");
diff --git a/core/java/android/app/admin/PolicyUpdateReceiver.java b/core/java/android/app/admin/PolicyUpdateReceiver.java
index 58f4f1b..b5d9286 100644
--- a/core/java/android/app/admin/PolicyUpdateReceiver.java
+++ b/core/java/android/app/admin/PolicyUpdateReceiver.java
@@ -19,6 +19,7 @@
import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
+import android.annotation.TestApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -112,31 +113,37 @@
"android.app.admin.extra.ACCOUNT_TYPE";
/**
+ * String extra containing the policy identifier.
+ *
* @hide
*/
- public static final String EXTRA_POLICY_CHANGED_KEY =
- "android.app.admin.extra.POLICY_CHANGED_KEY";
-
- /**
- * @hide
- */
+ @TestApi
public static final String EXTRA_POLICY_KEY = "android.app.admin.extra.POLICY_KEY";
/**
+ * Bundle extra containing additional information related to a policy.
+ *
* @hide
*/
+ @TestApi
public static final String EXTRA_POLICY_BUNDLE_KEY =
"android.app.admin.extra.POLICY_BUNDLE_KEY";
/**
+ * Int extra containing the {@link PolicyUpdateResult} code.
+ *
* @hide
*/
+ @TestApi
public static final String EXTRA_POLICY_UPDATE_RESULT_KEY =
"android.app.admin.extra.POLICY_UPDATE_RESULT_KEY";
/**
+ * Int extra containing the target user this policy update applies to.
+ *
* @hide
*/
+ @TestApi
public static final String EXTRA_POLICY_TARGET_USER_ID =
"android.app.admin.extra.POLICY_TARGET_USER_ID";
diff --git a/core/java/android/app/admin/TargetUser.java b/core/java/android/app/admin/TargetUser.java
index ed4fae0..ce6f32b 100644
--- a/core/java/android/app/admin/TargetUser.java
+++ b/core/java/android/app/admin/TargetUser.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import java.util.Objects;
@@ -29,23 +30,35 @@
*/
public final class TargetUser {
/**
+ * Indicates that the policy relates to the user the admin is installed on.
+ *
* @hide
*/
+ @TestApi
public static final int LOCAL_USER_ID = -1;
/**
+ * For admins of profiles, this indicates that the policy relates to the parent profile.
+ *
* @hide
*/
+ @TestApi
public static final int PARENT_USER_ID = -2;
/**
+ * This indicates the policy is a global policy.
+ *
* @hide
*/
+ @TestApi
public static final int GLOBAL_USER_ID = -3;
/**
+ * Indicates that the policy relates to some unknown user on the device.
+ *
* @hide
*/
+ @TestApi
public static final int UNKNOWN_USER_ID = -3;
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0d330ce..fcffc6f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -7384,7 +7384,6 @@
* @throws IllegalArgumentException if the given device ID is not a valid ID of the default
* device or a virtual device.
*
- * @see #isDeviceContext()
* @see #createDeviceContext(int)
* @hide
*/
@@ -7408,26 +7407,8 @@
* </p>
*
* <p>
- * This method will only return a reliable value for this instance if
- * {@link Context#isDeviceContext()} is {@code true}. The system can assign an arbitrary device
- * id value for Contexts not logically associated with a device.
- * </p>
- *
- * @return the ID of the device this context is associated with.
- * @see #isDeviceContext()
- * @see #createDeviceContext(int)
- * @see #registerDeviceIdChangeListener(Executor, IntConsumer)
- */
- public int getDeviceId() {
- throw new RuntimeException("Not implemented. Must override in a subclass.");
- }
-
- /**
- * Indicates whether the value of {@link Context#getDeviceId()} can be relied upon for
- * this instance. It will return {@code true} for Contexts created by
- * {@link Context#createDeviceContext(int)} which reference a valid device ID, as well as for
- * UI and Display Contexts.
- * <p>
+ * This method will only return a reliable value for this instance if it was created with
+ * {@link Context#createDeviceContext(int)}, or if this instance is a UI or Display Context.
* Contexts created with {@link Context#createDeviceContext(int)} will have an explicit
* device association, which will never change, even if the underlying device is closed or is
* removed. UI Contexts and Display Contexts are
@@ -7437,15 +7418,12 @@
* logically associated with a device.
* </p>
*
- * @return {@code true} if {@link Context#getDeviceId()} is reliable, {@code false} otherwise.
- *
+ * @return the ID of the device this context is associated with.
* @see #createDeviceContext(int)
- * @see #getDeviceId()}
- * @see #createDisplayContext(Display)
+ * @see #registerDeviceIdChangeListener(Executor, IntConsumer)
* @see #isUiContext()
*/
-
- public boolean isDeviceContext() {
+ public int getDeviceId() {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -7464,7 +7442,6 @@
* @param listener The listener {@code IntConsumer} to call which will receive the updated
* device ID.
*
- * @see Context#isDeviceContext()
* @see Context#getDeviceId()
* @see Context#createDeviceContext(int)
*/
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index a103128..91be664 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1201,11 +1201,6 @@
}
@Override
- public boolean isDeviceContext() {
- return mBase.isDeviceContext();
- }
-
- @Override
public void registerDeviceIdChangeListener(@NonNull @CallbackExecutor Executor executor,
@NonNull IntConsumer listener) {
mBase.registerDeviceIdChangeListener(executor, listener);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index cfd291f..2b4ea70 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2914,10 +2914,10 @@
* <li>{@code requireUserAction} is set to {@link #USER_ACTION_NOT_REQUIRED}.</li>
* <li>The app being installed targets:
* <ul>
- * <li>{@link android.os.Build.VERSION_CODES#Q API 29} or higher on
- * Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li>
- * <li>{@link android.os.Build.VERSION_CODES#R API 30} or higher after
- * Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li>
+ * <li>{@link android.os.Build.VERSION_CODES#R API 30} or higher on
+ * Android T ({@link android.os.Build.VERSION_CODES#TIRAMISU API 33})</li>
+ * <li>{@link android.os.Build.VERSION_CODES#S API 31} or higher <b>after</b>
+ * Android T ({@link android.os.Build.VERSION_CODES#TIRAMISU API 33})</li>
* </ul>
* </li>
* <li>The installer is:
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index 07473d2..ff7fc36 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -332,6 +332,7 @@
@Nullable CancellationSignal cancellationSignal,
@CallbackExecutor @NonNull Executor executor,
@NonNull OutcomeReceiver<Void, ClearCredentialStateException> callback) {
+ requireNonNull(request, "request must not be null");
requireNonNull(executor, "executor must not be null");
requireNonNull(callback, "callback must not be null");
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 19e759ca..5fb699c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10323,7 +10323,7 @@
/**
* If active unlock triggers on unlock intents, then also request active unlock on
- * these wake-up reasons. See PowerManager.WakeReason for value mappings.
+ * these wake-up reasons. See {@link PowerManager.WakeReason} for value mappings.
* WakeReasons should be separated by a pipe. For example: "0|3" or "0". If this
* setting should be disabled, then this should be set to an empty string. A null value
* will use the system default value (WAKE_REASON_UNFOLD_DEVICE).
@@ -10333,6 +10333,17 @@
"active_unlock_wakeups_considered_unlock_intents";
/**
+ * If active unlock triggers and succeeds on these wakeups, force dismiss keyguard on
+ * these wake reasons. See {@link PowerManager#WakeReason} for value mappings.
+ * WakeReasons should be separated by a pipe. For example: "0|3" or "0". If this
+ * setting should be disabled, then this should be set to an empty string. A null value
+ * will use the system default value (WAKE_REASON_UNFOLD_DEVICE).
+ * @hide
+ */
+ public static final String ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD =
+ "active_unlock_wakeups_to_force_dismiss_keyguard";
+
+ /**
* Whether the assist gesture should be enabled.
*
* @hide
diff --git a/core/java/android/service/credentials/CredentialEntry.java b/core/java/android/service/credentials/CredentialEntry.java
index b6c13c4..7e98bc7 100644
--- a/core/java/android/service/credentials/CredentialEntry.java
+++ b/core/java/android/service/credentials/CredentialEntry.java
@@ -107,6 +107,7 @@
}
private CredentialEntry(@NonNull Parcel in) {
+ requireNonNull(in, "parcel must not be null");
mType = in.readString8();
mSlice = in.readTypedObject(Slice.CREATOR);
mBeginGetCredentialOption = in.readTypedObject(BeginGetCredentialOption.CREATOR);
diff --git a/core/java/android/service/credentials/CredentialProviderInfo.java b/core/java/android/service/credentials/CredentialProviderInfo.java
index 75ba525..b5464db 100644
--- a/core/java/android/service/credentials/CredentialProviderInfo.java
+++ b/core/java/android/service/credentials/CredentialProviderInfo.java
@@ -16,6 +16,8 @@
package android.service.credentials;
+import static java.util.Objects.requireNonNull;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -112,10 +114,9 @@
"Provider is not a valid system provider: " + serviceInfo);
}
}
-
mIsSystemProvider = isSystemProvider;
- mContext = context;
- mServiceInfo = serviceInfo;
+ mContext = requireNonNull(context, "context must not be null");
+ mServiceInfo = requireNonNull(serviceInfo, "serviceInfo must not be null");
mCapabilities = new ArrayList<>();
mIcon = mServiceInfo.loadIcon(mContext.getPackageManager());
mLabel =
@@ -300,6 +301,7 @@
@NonNull Context context,
@UserIdInt int userId,
boolean disableSystemAppVerificationForTests) {
+ requireNonNull(context, "context must not be null");
final List<CredentialProviderInfo> providerInfos = new ArrayList<>();
for (ServiceInfo si :
getAvailableSystemServiceInfos(
@@ -381,6 +383,8 @@
int userId,
boolean disableSystemAppVerificationForTests,
int providerFilter) {
+ requireNonNull(context, "context must not be null");
+
// Get the device policy.
PackagePolicy pp = getDeviceManagerPolicy(context);
diff --git a/core/java/android/service/credentials/GetCredentialRequest.java b/core/java/android/service/credentials/GetCredentialRequest.java
index 7cdccc6..4f13922 100644
--- a/core/java/android/service/credentials/GetCredentialRequest.java
+++ b/core/java/android/service/credentials/GetCredentialRequest.java
@@ -23,6 +23,8 @@
import com.android.internal.util.AnnotationValidations;
+import java.util.Objects;
+
/**
* Request for getting user's credential from a given credential provider.
*
@@ -43,8 +45,10 @@
public GetCredentialRequest(@NonNull CallingAppInfo callingAppInfo,
@NonNull CredentialOption credentialOption) {
- this.mCallingAppInfo = callingAppInfo;
- this.mCredentialOption = credentialOption;
+ this.mCallingAppInfo = Objects.requireNonNull(callingAppInfo,
+ "callingAppInfo must not be null");
+ this.mCredentialOption = Objects.requireNonNull(credentialOption,
+ "credentialOption must not be null");
}
private GetCredentialRequest(@NonNull Parcel in) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 00161c0..d21e5df 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -60,7 +60,6 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -180,8 +179,6 @@
private final ArrayList<Engine> mActiveEngines
= new ArrayList<Engine>();
- private Handler mBackgroundHandler;
- private HandlerThread mBackgroundThread;
static final class WallpaperCommand {
String action;
@@ -201,6 +198,14 @@
*/
public class Engine {
IWallpaperEngineWrapper mIWallpaperEngine;
+ final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
+ final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
+
+ // 2D matrix [x][y] to represent a page of a portion of a window
+ EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
+ Bitmap mLastScreenshot;
+ int mLastWindowPage = -1;
+ private boolean mResetWindowPages;
// Copies from mIWallpaperEngine.
HandlerCaller mCaller;
@@ -261,27 +266,11 @@
final Object mLock = new Object();
boolean mOffsetMessageEnqueued;
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
float mPendingXOffset;
float mPendingYOffset;
float mPendingXOffsetStep;
float mPendingYOffsetStep;
-
- /**
- * local color extraction related fields
- * to be used by the background thread only (except the atomic boolean)
- */
- final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4);
- final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4);
- private long mLastProcessLocalColorsTimestamp;
- private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
- private int mPixelCopyCount = 0;
- // 2D matrix [x][y] to represent a page of a portion of a window
- EngineWindowPage[] mWindowPages = new EngineWindowPage[0];
- Bitmap mLastScreenshot;
- private boolean mResetWindowPages;
-
boolean mPendingSync;
MotionEvent mPendingMove;
boolean mIsInAmbientMode;
@@ -290,8 +279,12 @@
private long mLastColorInvalidation;
private final Runnable mNotifyColorsChanged = this::notifyColorsChanged;
+ // used to throttle processLocalColors
+ private long mLastProcessLocalColorsTimestamp;
+ private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false);
private final Supplier<Long> mClockFunction;
private final Handler mHandler;
+
private Display mDisplay;
private Context mDisplayContext;
private int mDisplayState;
@@ -861,7 +854,7 @@
+ "was not established.");
}
mResetWindowPages = true;
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingXOffsetStep);
} catch (RemoteException e) {
Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e);
}
@@ -1399,7 +1392,7 @@
resetWindowPages();
mSession.finishDrawing(mWindow, null /* postDrawTransaction */,
Integer.MAX_VALUE);
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingXOffsetStep);
}
reposition();
reportEngineShown(shouldWaitForEngineShown());
@@ -1543,7 +1536,7 @@
if (!mDestroyed) {
mVisible = visible;
reportVisibility();
- if (mReportedVisible) processLocalColors();
+ if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
} else {
AnimationHandler.requestAnimatorsEnabled(visible, this);
}
@@ -1627,44 +1620,31 @@
}
// setup local color extraction data
- processLocalColors();
+ processLocalColors(xOffset, xOffsetStep);
}
/**
* Thread-safe util to call {@link #processLocalColorsInternal} with a minimum interval of
* {@link #PROCESS_LOCAL_COLORS_INTERVAL_MS} between two calls.
*/
- private void processLocalColors() {
+ private void processLocalColors(float xOffset, float xOffsetStep) {
if (mProcessLocalColorsPending.compareAndSet(false, true)) {
final long now = mClockFunction.get();
final long timeSinceLastColorProcess = now - mLastProcessLocalColorsTimestamp;
final long timeToWait = Math.max(0,
PROCESS_LOCAL_COLORS_INTERVAL_MS - timeSinceLastColorProcess);
- mBackgroundHandler.postDelayed(() -> {
+ mHandler.postDelayed(() -> {
mLastProcessLocalColorsTimestamp = now + timeToWait;
mProcessLocalColorsPending.set(false);
- processLocalColorsInternal();
+ processLocalColorsInternal(xOffset, xOffsetStep);
}, timeToWait);
}
}
- private void processLocalColorsInternal() {
+ private void processLocalColorsInternal(float xOffset, float xOffsetStep) {
// implemented by the wallpaper
if (supportsLocalColorExtraction()) return;
- if (!mBackgroundHandler.getLooper().isCurrentThread()) {
- throw new IllegalStateException(
- "ProcessLocalColors should be called from the background thread");
- }
- float xOffset;
- float xOffsetStep;
- float wallpaperDimAmount;
- synchronized (mLock) {
- xOffset = mPendingXOffset;
- xOffsetStep = mPendingXOffsetStep;
- wallpaperDimAmount = mWallpaperDimAmount;
- }
-
if (DEBUG) {
Log.d(TAG, "processLocalColors " + xOffset + " of step "
+ xOffsetStep);
@@ -1727,7 +1707,7 @@
xPage = mWindowPages.length - 1;
}
current = mWindowPages[xPage];
- updatePage(current, xPage, xPages, wallpaperDimAmount);
+ updatePage(current, xPage, xPages, finalXOffsetStep);
Trace.endSection();
}
@@ -1747,21 +1727,16 @@
}
}
- /**
- * Must be called with the surface lock held.
- * Must not be called if the surface is not valid.
- * Will unlock the surface when done using it.
- */
void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages,
- float wallpaperDimAmount) {
-
+ float xOffsetStep) {
// in case the clock is zero, we start with negative time
long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION;
long lapsed = current - currentPage.getLastUpdateTime();
// Always update the page when the last update time is <= 0
// This is important especially when the device first boots
- if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) return;
-
+ if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) {
+ return;
+ }
Surface surface = mSurfaceHolder.getSurface();
if (!surface.isValid()) return;
boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y;
@@ -1777,41 +1752,32 @@
Bitmap screenShot = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
final Bitmap finalScreenShot = screenShot;
- final String pixelCopySectionName = "WallpaperService#pixelCopy";
- final int pixelCopyCount = mPixelCopyCount++;
- Trace.beginAsyncSection(pixelCopySectionName, pixelCopyCount);
- try {
- PixelCopy.request(surface, screenShot, (res) -> {
- mSurfaceHolder.mSurfaceLock.unlock();
- Trace.endAsyncSection(pixelCopySectionName, pixelCopyCount);
- if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
- if (res != PixelCopy.SUCCESS) {
- Bitmap lastBitmap = currentPage.getBitmap();
- // assign the last bitmap taken for now
- currentPage.setBitmap(mLastScreenshot);
- Bitmap lastScreenshot = mLastScreenshot;
- if (lastScreenshot != null && !lastScreenshot.isRecycled()
- && !Objects.equals(lastBitmap, lastScreenshot)) {
- updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount);
- }
- } else {
- mLastScreenshot = finalScreenShot;
- // going to hold this lock for a while
- currentPage.setBitmap(finalScreenShot);
- currentPage.setLastUpdateTime(current);
- updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount);
+ Trace.beginSection("WallpaperService#pixelCopy");
+ PixelCopy.request(surface, screenShot, (res) -> {
+ Trace.endSection();
+ if (DEBUG) Log.d(TAG, "result of pixel copy is " + res);
+ if (res != PixelCopy.SUCCESS) {
+ Bitmap lastBitmap = currentPage.getBitmap();
+ // assign the last bitmap taken for now
+ currentPage.setBitmap(mLastScreenshot);
+ Bitmap lastScreenshot = mLastScreenshot;
+ if (lastScreenshot != null && !lastScreenshot.isRecycled()
+ && !Objects.equals(lastBitmap, lastScreenshot)) {
+ updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
}
- }, mBackgroundHandler);
- } catch (IllegalArgumentException e) {
- // this can potentially happen if the surface is invalidated right between the
- // surface.isValid() check and the PixelCopy operation.
- // in this case, stop: we'll compute colors on the next processLocalColors call.
- Log.i(TAG, "Cancelling processLocalColors: exception caught during PixelCopy");
- }
+ } else {
+ mLastScreenshot = finalScreenShot;
+ // going to hold this lock for a while
+ currentPage.setBitmap(finalScreenShot);
+ currentPage.setLastUpdateTime(current);
+ updatePageColors(currentPage, pageIndx, numPages, xOffsetStep);
+ }
+ }, mHandler);
+
}
// locked by the passed page
- private void updatePageColors(
- EngineWindowPage page, int pageIndx, int numPages, float wallpaperDimAmount) {
+ private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages,
+ float xOffsetStep) {
if (page.getBitmap() == null) return;
Trace.beginSection("WallpaperService#updatePageColors");
if (DEBUG) {
@@ -1834,7 +1800,7 @@
Log.e(TAG, "Error creating page local color bitmap", e);
continue;
}
- WallpaperColors color = WallpaperColors.fromBitmap(target, wallpaperDimAmount);
+ WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount);
target.recycle();
WallpaperColors currentColor = page.getColors(area);
@@ -1851,14 +1817,12 @@
+ " local color callback for area" + area + " for page " + pageIndx
+ " of " + numPages);
}
- mHandler.post(() -> {
- try {
- mConnection.onLocalWallpaperColorsChanged(area, color,
- mDisplayContext.getDisplayId());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
- }
- });
+ try {
+ mConnection.onLocalWallpaperColorsChanged(area, color,
+ mDisplayContext.getDisplayId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e);
+ }
}
}
Trace.endSection();
@@ -1888,6 +1852,7 @@
if (supportsLocalColorExtraction()) return;
if (!mResetWindowPages) return;
mResetWindowPages = false;
+ mLastWindowPage = -1;
for (int i = 0; i < mWindowPages.length; i++) {
mWindowPages[i].setLastUpdateTime(0L);
}
@@ -1913,10 +1878,12 @@
if (DEBUG) {
Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions);
}
- mBackgroundHandler.post(() -> {
+ mHandler.post(() -> {
mLocalColorsToAdd.addAll(regions);
- processLocalColors();
+ processLocalColors(mPendingXOffset, mPendingYOffset);
});
+
+
}
/**
@@ -1926,7 +1893,7 @@
*/
public void removeLocalColorsAreas(@NonNull List<RectF> regions) {
if (supportsLocalColorExtraction()) return;
- mBackgroundHandler.post(() -> {
+ mHandler.post(() -> {
float step = mPendingXOffsetStep;
mLocalColorsToAdd.removeAll(regions);
mLocalColorAreas.removeAll(regions);
@@ -2583,10 +2550,6 @@
@Override
public void onCreate() {
Trace.beginSection("WPMS.onCreate");
- final String localColorExtractorThreadName = "DefaultWallpaperLocalColorExtractor";
- mBackgroundThread = new HandlerThread(localColorExtractorThreadName);
- mBackgroundThread.start();
- mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
super.onCreate();
Trace.endSection();
}
@@ -2599,7 +2562,6 @@
mActiveEngines.get(i).detach();
}
mActiveEngines.clear();
- mBackgroundThread.quitSafely();
Trace.endSection();
}
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 18fdb83..f6309f2 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -32,6 +32,8 @@
import android.telephony.Annotation.SimActivationState;
import android.telephony.Annotation.SrvccState;
import android.telephony.TelephonyManager.DataEnabledReason;
+import android.telephony.TelephonyManager.EmergencyCallbackModeStopReason;
+import android.telephony.TelephonyManager.EmergencyCallbackModeType;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.MediaQualityStatus;
@@ -1304,8 +1306,6 @@
// default implementation empty
}
-
-
/**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
@@ -1669,6 +1669,18 @@
public final void onMediaQualityStatusChanged(MediaQualityStatus mediaQualityStatus) {
// not support. Can't override. Use TelephonyCallback.
}
+
+ /** @hide */
+ public final void onCallBackModeStarted(
+ @TelephonyManager.EmergencyCallbackModeType int type) {
+ // not support. Can't override. Use TelephonyCallback.
+ }
+
+ /** @hide */
+ public final void onCallBackModeStopped(@EmergencyCallbackModeType int type,
+ @EmergencyCallbackModeStopReason int reason) {
+ // not support. Can't override. Use TelephonyCallback.
+ }
}
private void log(String s) {
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index f8df668..7ada058 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -612,6 +612,20 @@
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int EVENT_MEDIA_QUALITY_STATUS_CHANGED = 39;
+
+ /**
+ * Event for changes to the Emergency callback mode
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
+ *
+ * @see EmergencyCallbackModeListener#onCallbackModeStarted(int)
+ * @see EmergencyCallbackModeListener#onCallbackModeStopped(int, int)
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int EVENT_EMERGENCY_CALLBACK_MODE_CHANGED = 40;
+
/**
* @hide
*/
@@ -654,7 +668,8 @@
EVENT_LEGACY_CALL_STATE_CHANGED,
EVENT_LINK_CAPACITY_ESTIMATE_CHANGED,
EVENT_TRIGGER_NOTIFY_ANBR,
- EVENT_MEDIA_QUALITY_STATUS_CHANGED
+ EVENT_MEDIA_QUALITY_STATUS_CHANGED,
+ EVENT_EMERGENCY_CALLBACK_MODE_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
public @interface TelephonyEvent {
@@ -1568,6 +1583,53 @@
}
/**
+ * Interface for emergency callback mode listener.
+ *
+ * @hide
+ */
+ public interface EmergencyCallbackModeListener {
+ /**
+ * Indicates that Callback Mode has been started.
+ * <p>
+ * This method will be called when an emergency sms/emergency call is sent
+ * and the callback mode is supported by the carrier.
+ * If an emergency SMS is transmitted during callback mode for SMS, this API will be called
+ * once again with TelephonyManager#EMERGENCY_CALLBACK_MODE_SMS.
+ *
+ * @param type for callback mode entry
+ * See {@link TelephonyManager.EmergencyCallbackModeType}.
+ * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_CALL
+ * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_SMS
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ void onCallBackModeStarted(@TelephonyManager.EmergencyCallbackModeType int type);
+
+ /**
+ * Indicates that Callback Mode has been stopped.
+ * <p>
+ * This method will be called when the callback mode timer expires or when
+ * a normal call/SMS is sent
+ *
+ * @param type for callback mode entry
+ * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_CALL
+ * @see TelephonyManager#EMERGENCY_CALLBACK_MODE_SMS
+ *
+ * @param reason for changing callback mode
+ *
+ * @see TelephonyManager#STOP_REASON_UNKNOWN
+ * @see TelephonyManager#STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED
+ * @see TelephonyManager#STOP_REASON_NORMAL_SMS_SENT
+ * @see TelephonyManager#STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED
+ * @see TelephonyManager#STOP_REASON_EMERGENCY_SMS_SENT
+ * @see TelephonyManager#STOP_REASON_TIMER_EXPIRED
+ * @see TelephonyManager#STOP_REASON_USER_ACTION
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ void onCallBackModeStopped(@TelephonyManager.EmergencyCallbackModeType int type,
+ @TelephonyManager.EmergencyCallbackModeStopReason int reason);
+ }
+
+ /**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
* <p>
@@ -1935,5 +1997,27 @@
() -> mExecutor.execute(() -> listener.onMediaQualityStatusChanged(
mediaQualityStatus)));
}
+
+ public void onCallBackModeStarted(@TelephonyManager.EmergencyCallbackModeType int type) {
+ EmergencyCallbackModeListener listener =
+ (EmergencyCallbackModeListener) mTelephonyCallbackWeakRef.get();
+ Log.d(LOG_TAG, "onCallBackModeStarted:type=" + type + ", listener=" + listener);
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onCallBackModeStarted(type)));
+ }
+
+ public void onCallBackModeStopped(@TelephonyManager.EmergencyCallbackModeType int type,
+ @TelephonyManager.EmergencyCallbackModeStopReason int reason) {
+ EmergencyCallbackModeListener listener =
+ (EmergencyCallbackModeListener) mTelephonyCallbackWeakRef.get();
+ Log.d(LOG_TAG, "onCallBackModeStopped:type=" + type
+ + ", reason=" + reason + ", listener=" + listener);
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onCallBackModeStopped(type, reason)));
+ }
}
}
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 8b24e07..f648ad4 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -1113,6 +1113,11 @@
eventList.add(TelephonyCallback.EVENT_MEDIA_QUALITY_STATUS_CHANGED);
}
+ if (telephonyCallback instanceof TelephonyCallback.EmergencyCallbackModeListener) {
+ eventList.add(TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED);
+ }
+
+
return eventList;
}
@@ -1539,4 +1544,43 @@
throw re.rethrowFromSystemServer();
}
}
+
+ /**
+ * Notify Callback Mode has been started.
+ * @param phoneId Sender phone ID.
+ * @param subId Sender subscription ID.
+ * @param type for callback mode entry.
+ * See {@link TelephonyManager.EmergencyCallbackModeType}.
+ */
+ public void notifyCallBackModeStarted(int phoneId, int subId,
+ @TelephonyManager.EmergencyCallbackModeType int type) {
+ try {
+ Log.d(TAG, "notifyCallBackModeStarted:type=" + type);
+ sRegistry.notifyCallbackModeStarted(phoneId, subId, type);
+ } catch (RemoteException ex) {
+ // system process is dead
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Notify Callback Mode has been stopped.
+ * @param phoneId Sender phone ID.
+ * @param subId Sender subscription ID.
+ * @param type for callback mode entry.
+ * See {@link TelephonyManager.EmergencyCallbackModeType}.
+ * @param reason for changing callback mode.
+ * See {@link TelephonyManager.EmergencyCallbackModeStopReason}.
+ */
+ public void notifyCallbackModeStopped(int phoneId, int subId,
+ @TelephonyManager.EmergencyCallbackModeType int type,
+ @TelephonyManager.EmergencyCallbackModeStopReason int reason) {
+ try {
+ Log.d(TAG, "notifyCallbackModeStopped:type=" + type + ", reason=" + reason);
+ sRegistry.notifyCallbackModeStopped(phoneId, subId, type, reason);
+ } catch (RemoteException ex) {
+ // system process is dead
+ throw ex.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c2afd20..7d18bf0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10199,6 +10199,7 @@
setNotifiedContentCaptureAppeared();
if (ai != null) {
+ makeParentImportantAndNotifyAppearedEventIfNeed();
ai.delayNotifyContentCaptureEvent(session, this, appeared);
} else {
if (DEBUG_CONTENT_CAPTURE) {
@@ -10226,6 +10227,22 @@
}
}
+ private void makeParentImportantAndNotifyAppearedEventIfNeed() {
+ // If view sent the appeared event to Content Capture, Content Capture also
+ // would like to receive its parents' appeared events. So checks its parents
+ // whether the appeared event is sent or not. If not, send the appeared event.
+ final ViewParent parent = getParent();
+ if (parent instanceof View) {
+ View p = ((View) parent);
+ if (p.getNotifiedContentCaptureAppeared()) {
+ return;
+ }
+ // Set important for content capture in the cache.
+ p.mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK;
+ p.notifyAppearedOrDisappearedForContentCaptureIfNeeded(/* appeared */ true);
+ }
+ }
+
private void setNotifiedContentCaptureAppeared() {
mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED;
mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED;
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index 63785f2..134a917 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -139,15 +139,6 @@
}
@Override
- public boolean isDeviceContext() {
- Context context = mContext.get();
- if (context != null) {
- return context.isDeviceContext();
- }
- return false;
- }
-
- @Override
public boolean isConfigurationContext() {
Context context = mContext.get();
if (context != null) {
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 3e9f1cb..03cfd4f 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -78,4 +78,6 @@
void onAllowedNetworkTypesChanged(in int reason, in long allowedNetworkType);
void onLinkCapacityEstimateChanged(in List<LinkCapacityEstimate> linkCapacityEstimateList);
void onMediaQualityStatusChanged(in MediaQualityStatus mediaQualityStatus);
+ void onCallBackModeStarted(int type);
+ void onCallBackModeStopped(int type, int reason);
}
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index fd9239d..8a02dd6 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -117,4 +117,7 @@
String pkg, String featureId);
void removeCarrierConfigChangeListener(ICarrierConfigChangeListener listener, String pkg);
void notifyCarrierConfigChanged(int phoneId, int subId, int carrierId, int specificCarrierId);
+
+ void notifyCallbackModeStarted(int phoneId, int subId, int type);
+ void notifyCallbackModeStopped(int phoneId, int subId, int type, int reason);
}
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 1910331..b1dab85 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -18,29 +18,25 @@
#define LOG_TAG "AudioRecord-JNI"
-#include <inttypes.h>
-#include <jni.h>
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-
-#include <utils/Log.h>
-#include <media/AudioRecord.h>
-#include <media/MicrophoneInfo.h>
-#include <vector>
-
#include <android/content/AttributionSourceState.h>
#include <android_os_Parcel.h>
-
+#include <inttypes.h>
+#include <jni.h>
+#include <media/AudioRecord.h>
+#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
+#include <utils/Log.h>
+
+#include <vector>
#include "android_media_AudioAttributes.h"
-#include "android_media_AudioFormat.h"
#include "android_media_AudioErrors.h"
+#include "android_media_AudioFormat.h"
#include "android_media_DeviceCallback.h"
#include "android_media_JNIUtils.h"
#include "android_media_MediaMetricsJNI.h"
#include "android_media_MicrophoneInfo.h"
-
+#include "core_jni_helpers.h"
// ----------------------------------------------------------------------------
@@ -719,7 +715,7 @@
}
jint jStatus = AUDIO_JAVA_SUCCESS;
- std::vector<media::MicrophoneInfo> activeMicrophones;
+ std::vector<media::MicrophoneInfoFw> activeMicrophones;
status_t status = lpRecorder->getActiveMicrophones(&activeMicrophones);
if (status != NO_ERROR) {
ALOGE_IF(status != NO_ERROR, "AudioRecord::getActiveMicrophones error %d", status);
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 75f8402..8ba4eed 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -28,7 +28,6 @@
#include <media/AudioContainers.h>
#include <media/AudioPolicy.h>
#include <media/AudioSystem.h>
-#include <media/MicrophoneInfo.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <system/audio.h>
@@ -2424,7 +2423,7 @@
}
jint jStatus;
- std::vector<media::MicrophoneInfo> microphones;
+ std::vector<media::MicrophoneInfoFw> microphones;
status_t status = AudioSystem::getMicrophones(µphones);
if (status != NO_ERROR) {
ALOGE("AudioSystem::getMicrophones error %d", status);
diff --git a/core/jni/android_media_MicrophoneInfo.cpp b/core/jni/android_media_MicrophoneInfo.cpp
index b70190f..65e30d8 100644
--- a/core/jni/android_media_MicrophoneInfo.cpp
+++ b/core/jni/android_media_MicrophoneInfo.cpp
@@ -15,6 +15,9 @@
*/
#include "android_media_MicrophoneInfo.h"
+
+#include <media/AidlConversion.h>
+
#include "android_media_AudioErrors.h"
#include "core_jni_helpers.h"
@@ -46,8 +49,17 @@
namespace android {
jint convertMicrophoneInfoFromNative(JNIEnv *env, jobject *jMicrophoneInfo,
- const media::MicrophoneInfo *microphoneInfo)
-{
+ const media::MicrophoneInfoFw *microphoneInfo) {
+ // The Java object uses the same enum values as the C enum values, which are
+ // generated from HIDL. Thus, we can use the legacy structure as the source for
+ // creating the Java object. Once we start removing legacy types, we can add
+ // direct converters between Java and AIDL, this will eliminate the need
+ // to have JNI code like this one.
+ auto conv = aidl2legacy_MicrophoneInfoFw_audio_microphone_characteristic_t(*microphoneInfo);
+ if (!conv.ok()) {
+ return nativeToJavaStatus(conv.error());
+ }
+
jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
jstring jDeviceId = NULL;
jstring jAddress = NULL;
@@ -56,36 +68,23 @@
jobject jFrequencyResponses = NULL;
jobject jChannelMappings = NULL;
- jDeviceId = env->NewStringUTF(microphoneInfo->getDeviceId().c_str());
- jAddress = env->NewStringUTF(microphoneInfo->getAddress().c_str());
- if (microphoneInfo->getGeometricLocation().size() != 3 ||
- microphoneInfo->getOrientation().size() != 3) {
- jStatus = nativeToJavaStatus(BAD_VALUE);
- goto exit;
- }
- jGeometricLocation = env->NewObject(gMicrophoneInfoCoordinateClass,
- gMicrophoneInfoCoordinateCstor,
- microphoneInfo->getGeometricLocation()[0],
- microphoneInfo->getGeometricLocation()[1],
- microphoneInfo->getGeometricLocation()[2]);
- jOrientation = env->NewObject(gMicrophoneInfoCoordinateClass,
- gMicrophoneInfoCoordinateCstor,
- microphoneInfo->getOrientation()[0],
- microphoneInfo->getOrientation()[1],
- microphoneInfo->getOrientation()[2]);
+ const auto &micInfo = conv.value();
+ jDeviceId = env->NewStringUTF(micInfo.device_id);
+ jAddress = env->NewStringUTF(micInfo.address);
+ jGeometricLocation =
+ env->NewObject(gMicrophoneInfoCoordinateClass, gMicrophoneInfoCoordinateCstor,
+ micInfo.geometric_location.x, micInfo.geometric_location.y,
+ micInfo.geometric_location.z);
+ jOrientation =
+ env->NewObject(gMicrophoneInfoCoordinateClass, gMicrophoneInfoCoordinateCstor,
+ micInfo.orientation.x, micInfo.orientation.y, micInfo.orientation.z);
// Create a list of Pair for frequency response.
- if (microphoneInfo->getFrequencyResponses().size() != 2 ||
- microphoneInfo->getFrequencyResponses()[0].size() !=
- microphoneInfo->getFrequencyResponses()[1].size()) {
- jStatus = nativeToJavaStatus(BAD_VALUE);
- goto exit;
- }
jFrequencyResponses = env->NewObject(gArrayListClass, gArrayListCstor);
- for (size_t i = 0; i < microphoneInfo->getFrequencyResponses()[0].size(); i++) {
- jobject jFrequency = env->NewObject(gFloatClass, gFloatCstor,
- microphoneInfo->getFrequencyResponses()[0][i]);
- jobject jResponse = env->NewObject(gFloatClass, gFloatCstor,
- microphoneInfo->getFrequencyResponses()[1][i]);
+ for (size_t i = 0; i < micInfo.num_frequency_responses; i++) {
+ jobject jFrequency =
+ env->NewObject(gFloatClass, gFloatCstor, micInfo.frequency_responses[0][i]);
+ jobject jResponse =
+ env->NewObject(gFloatClass, gFloatCstor, micInfo.frequency_responses[1][i]);
jobject jFrequencyResponse = env->NewObject(gPairClass, gPairCstor, jFrequency, jResponse);
env->CallBooleanMethod(jFrequencyResponses, gArrayListMethods.add, jFrequencyResponse);
env->DeleteLocalRef(jFrequency);
@@ -93,13 +92,9 @@
env->DeleteLocalRef(jFrequencyResponse);
}
// Create a list of Pair for channel mapping.
- if (microphoneInfo->getChannelMapping().size() != AUDIO_CHANNEL_COUNT_MAX) {
- jStatus = nativeToJavaStatus(BAD_VALUE);
- goto exit;
- }
- jChannelMappings = env->NewObject(gArrayListClass, gArrayListCstor);
- for (size_t i = 0; i < microphoneInfo->getChannelMapping().size(); i++) {
- int channelMappingType = microphoneInfo->getChannelMapping()[i];
+ const auto &channelMapping = micInfo.channel_mapping;
+ for (size_t i = 0; i < std::size(channelMapping); i++) {
+ int channelMappingType = channelMapping[i];
if (channelMappingType != AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED) {
jobject jChannelIndex = env->NewObject(gIntegerClass, gIntegerCstor, i);
jobject jChannelMappingType = env->NewObject(gIntegerClass, gIntegerCstor,
@@ -113,18 +108,11 @@
}
}
*jMicrophoneInfo = env->NewObject(gMicrophoneInfoClass, gMicrophoneInfoCstor, jDeviceId,
- microphoneInfo->getType(), jAddress,
- microphoneInfo->getDeviceLocation(),
- microphoneInfo->getDeviceGroup(),
- microphoneInfo->getIndexInTheGroup(),
- jGeometricLocation, jOrientation,
- jFrequencyResponses, jChannelMappings,
- microphoneInfo->getSensitivity(),
- microphoneInfo->getMaxSpl(),
- microphoneInfo->getMinSpl(),
- microphoneInfo->getDirectionality());
+ micInfo.device, jAddress, micInfo.location, micInfo.group,
+ micInfo.index_in_the_group, jGeometricLocation, jOrientation,
+ jFrequencyResponses, jChannelMappings, micInfo.sensitivity,
+ micInfo.max_spl, micInfo.min_spl, micInfo.directionality);
-exit:
if (jDeviceId != NULL) {
env->DeleteLocalRef(jDeviceId);
}
@@ -145,7 +133,6 @@
}
return jStatus;
}
-
}
int register_android_media_MicrophoneInfo(JNIEnv *env)
diff --git a/core/jni/android_media_MicrophoneInfo.h b/core/jni/android_media_MicrophoneInfo.h
index 241b6d0..dc531c6 100644
--- a/core/jni/android_media_MicrophoneInfo.h
+++ b/core/jni/android_media_MicrophoneInfo.h
@@ -17,8 +17,8 @@
#ifndef ANDROID_MEDIA_MICROPHONEINFO_H
#define ANDROID_MEDIA_MICROPHONEINFO_H
+#include <android/media/MicrophoneInfoFw.h>
#include <system/audio.h>
-#include <media/MicrophoneInfo.h>
#include "jni.h"
@@ -27,7 +27,7 @@
// Conversion from C++ MicrophoneInfo object to Java MicrophoneInfo object
extern jint convertMicrophoneInfoFromNative(JNIEnv *env, jobject *jMicrophoneInfo,
- const media::MicrophoneInfo *microphoneInfo);
+ const media::MicrophoneInfoFw *microphoneInfo);
} // namespace android
-#endif
\ No newline at end of file
+#endif
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a4818c7..2376baa 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5838,7 +5838,7 @@
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.CALL_AUDIO_INTERCEPTION"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged|role" />
<!-- @TestApi Allows an application to query audio related state.
@hide -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 0c2fc1d..68c8d41 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -470,15 +470,15 @@
<color name="system_error_container_light">#FFDAD5</color>
<color name="system_on_error_container_light">#410000</color>
<color name="system_primary_fixed_light">#D8E2FF</color>
- <color name="system_primary_fixed_darker_light">#ADC6FF</color>
+ <color name="system_primary_fixed_dim_light">#ADC6FF</color>
<color name="system_on_primary_fixed_light">#001A41</color>
<color name="system_on_primary_fixed_variant_light">#2B4678</color>
<color name="system_secondary_fixed_light">#DBE2F9</color>
- <color name="system_secondary_fixed_darker_light">#BFC6DC</color>
+ <color name="system_secondary_fixed_dim_light">#BFC6DC</color>
<color name="system_on_secondary_fixed_light">#141B2C</color>
<color name="system_on_secondary_fixed_variant_light">#3F4759</color>
<color name="system_tertiary_fixed_light">#FBD7FC</color>
- <color name="system_tertiary_fixed_darker_light">#DEBCDF</color>
+ <color name="system_tertiary_fixed_dim_light">#DEBCDF</color>
<color name="system_on_tertiary_fixed_light">#29132D</color>
<color name="system_on_tertiary_fixed_variant_light">#583E5B</color>
<color name="system_control_activated_light">#D8E2FF</color>
@@ -525,15 +525,15 @@
<color name="system_error_container_dark">#930001</color>
<color name="system_on_error_container_dark">#FFDAD5</color>
<color name="system_primary_fixed_dark">#D8E2FF</color>
- <color name="system_primary_fixed_darker_dark">#ADC6FF</color>
+ <color name="system_primary_fixed_dim_dark">#ADC6FF</color>
<color name="system_on_primary_fixed_dark">#001A41</color>
<color name="system_on_primary_fixed_variant_dark">#2B4678</color>
<color name="system_secondary_fixed_dark">#DBE2F9</color>
- <color name="system_secondary_fixed_darker_dark">#BFC6DC</color>
+ <color name="system_secondary_fixed_dim_dark">#BFC6DC</color>
<color name="system_on_secondary_fixed_dark">#141B2C</color>
<color name="system_on_secondary_fixed_variant_dark">#3F4759</color>
<color name="system_tertiary_fixed_dark">#FBD7FC</color>
- <color name="system_tertiary_fixed_darker_dark">#DEBCDF</color>
+ <color name="system_tertiary_fixed_dim_dark">#DEBCDF</color>
<color name="system_on_tertiary_fixed_dark">#29132D</color>
<color name="system_on_tertiary_fixed_variant_dark">#583E5B</color>
<color name="system_control_activated_dark">#2B4678</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8e5ae9c..81d095a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2189,6 +2189,8 @@
<bool name="config_enableDefaultNotesForWorkProfile">false</bool>
<!-- The name of the package that will hold the system financed device controller role. -->
<string name="config_systemFinancedDeviceController" translatable="false">com.android.devicelockcontroller</string>
+ <!-- The name of the package that will hold the call streaming role. -->
+ <string name="config_systemCallStreaming" translatable="false"></string>
<!-- The component name of the wear service class that will be started by the system server. -->
<string name="config_wearServiceComponent" translatable="false"></string>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 7d41f76..b23d5b4 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -148,6 +148,8 @@
<public name="config_defaultNotes" />
<!-- @hide @SystemApi -->
<public name="config_systemFinancedDeviceController" />
+ <!-- @hide @SystemApi -->
+ <public name="config_systemCallStreaming" />
</staging-public-group>
<staging-public-group type="dimen" first-id="0x01ca0000">
@@ -187,15 +189,15 @@
<public name="system_error_container_light" />
<public name="system_on_error_container_light" />
<public name="system_primary_fixed_light" />
- <public name="system_primary_fixed_darker_light" />
+ <public name="system_primary_fixed_dim_light" />
<public name="system_on_primary_fixed_light" />
<public name="system_on_primary_fixed_variant_light" />
<public name="system_secondary_fixed_light" />
- <public name="system_secondary_fixed_darker_light" />
+ <public name="system_secondary_fixed_dim_light" />
<public name="system_on_secondary_fixed_light" />
<public name="system_on_secondary_fixed_variant_light" />
<public name="system_tertiary_fixed_light" />
- <public name="system_tertiary_fixed_darker_light" />
+ <public name="system_tertiary_fixed_dim_light" />
<public name="system_on_tertiary_fixed_light" />
<public name="system_on_tertiary_fixed_variant_light" />
<public name="system_control_activated_light" />
@@ -242,15 +244,15 @@
<public name="system_error_container_dark"/>
<public name="system_on_error_container_dark"/>
<public name="system_primary_fixed_dark"/>
- <public name="system_primary_fixed_darker_dark"/>
+ <public name="system_primary_fixed_dim_dark"/>
<public name="system_on_primary_fixed_dark"/>
<public name="system_on_primary_fixed_variant_dark"/>
<public name="system_secondary_fixed_dark"/>
- <public name="system_secondary_fixed_darker_dark"/>
+ <public name="system_secondary_fixed_dim_dark"/>
<public name="system_on_secondary_fixed_dark"/>
<public name="system_on_secondary_fixed_variant_dark"/>
<public name="system_tertiary_fixed_dark"/>
- <public name="system_tertiary_fixed_darker_dark"/>
+ <public name="system_tertiary_fixed_dim_dark"/>
<public name="system_on_tertiary_fixed_dark"/>
<public name="system_on_tertiary_fixed_variant_dark"/>
<public name="system_control_activated_dark"/>
diff --git a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java
new file mode 100644
index 0000000..444e9f2
--- /dev/null
+++ b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.credentials;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.app.slice.Slice;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ICancellationSignal;
+import android.os.OutcomeReceiver;
+import android.os.RemoteException;
+import android.service.credentials.CredentialEntry;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CredentialManagerTest {
+ @Mock
+ private ICredentialManager mMockCredentialManagerService;
+
+ @Mock
+ private Activity mMockActivity;
+
+ private GetCredentialRequest mGetRequest;
+ private CreateCredentialRequest mCreateRequest;
+
+ private ClearCredentialStateRequest mClearRequest;
+ private RegisterCredentialDescriptionRequest mRegisterRequest;
+ private UnregisterCredentialDescriptionRequest mUnregisterRequest;
+
+ private CredentialManager mCredentialManager;
+ private Executor mExecutor;
+ private String mPackageName;
+
+ private static boolean bundleEquals(Bundle a, Bundle b) {
+ if (a == null && b == null) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ for (String aKey : a.keySet()) {
+ if (!Objects.equals(a.get(aKey), b.get(aKey))) {
+ return false;
+ }
+ }
+
+ for (String bKey : b.keySet()) {
+ if (!Objects.equals(b.get(bKey), a.get(bKey))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static void assertBundleEquals(Bundle a, Bundle b) {
+ assertThat(bundleEquals(a, b)).isTrue();
+ }
+
+ @Before
+ public void setup() {
+ mGetRequest = new GetCredentialRequest.Builder(Bundle.EMPTY).addCredentialOption(
+ new CredentialOption(Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY,
+ Bundle.EMPTY, false)).build();
+ mCreateRequest = new CreateCredentialRequest(Credential.TYPE_PASSWORD_CREDENTIAL,
+ Bundle.EMPTY, Bundle.EMPTY, false, false);
+ mClearRequest = new ClearCredentialStateRequest(Bundle.EMPTY);
+
+ final Slice slice = new Slice.Builder(Uri.parse("foo://bar"), null).addText("some text",
+ null, List.of(Slice.HINT_TITLE)).build();
+ mRegisterRequest = new RegisterCredentialDescriptionRequest(
+ new CredentialDescription(Credential.TYPE_PASSWORD_CREDENTIAL,
+ "{ \"foo\": \"bar\" }",
+ List.of(new CredentialEntry(Credential.TYPE_PASSWORD_CREDENTIAL, slice))));
+ mUnregisterRequest = new UnregisterCredentialDescriptionRequest(
+ new CredentialDescription(Credential.TYPE_PASSWORD_CREDENTIAL,
+ "{ \"foo\": \"bar\" }",
+ List.of(new CredentialEntry(Credential.TYPE_PASSWORD_CREDENTIAL, slice))));
+
+ final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ mCredentialManager = new CredentialManager(context, mMockCredentialManagerService);
+ mExecutor = Runnable::run;
+ mPackageName = context.getOpPackageName();
+ }
+
+ @Test
+ public void testGetCredential_nullRequest() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.getCredential(null, mMockActivity, null, mExecutor,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testGetCredential_nullActivity() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.getCredential(mGetRequest, null, null, mExecutor,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testGetCredential_nullExecutor() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.getCredential(mGetRequest, mMockActivity, null, null,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testGetCredential_nullCallback() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.getCredential(mGetRequest, mMockActivity, null, null,
+ null));
+ }
+
+ @Test
+ public void testGetCredential_noCredential() throws RemoteException {
+ ArgumentCaptor<IGetCredentialCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IGetCredentialCallback.class);
+ ArgumentCaptor<GetCredentialException> errorCaptor = ArgumentCaptor.forClass(
+ GetCredentialException.class);
+
+ OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeGetCredential(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.getCredential(mGetRequest, mMockActivity, null, mExecutor, callback);
+ verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
+
+ callbackCaptor.getValue().onError(GetCredentialException.TYPE_NO_CREDENTIAL,
+ "no credential found");
+ verify(callback).onError(errorCaptor.capture());
+
+ assertThat(errorCaptor.getValue().getType()).isEqualTo(
+ GetCredentialException.TYPE_NO_CREDENTIAL);
+ }
+
+ @Test
+ public void testGetCredential_alreadyCancelled() throws RemoteException {
+ final CancellationSignal cancellation = new CancellationSignal();
+ cancellation.cancel();
+
+ mCredentialManager.getCredential(mGetRequest, mMockActivity, cancellation, mExecutor,
+ result -> {
+ });
+
+ verify(mMockCredentialManagerService, never()).executeGetCredential(any(), any(), any());
+ }
+
+ @Test
+ public void testGetCredential_cancel() throws RemoteException {
+ final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
+ final CancellationSignal cancellation = new CancellationSignal();
+
+ OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeGetCredential(any(), any(), any())).thenReturn(
+ serviceSignal);
+
+ mCredentialManager.getCredential(mGetRequest, mMockActivity, cancellation, mExecutor,
+ callback);
+
+ verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
+
+ cancellation.cancel();
+ verify(serviceSignal).cancel();
+ }
+
+ @Test
+ public void testGetCredential_success() throws RemoteException {
+ final Credential cred = new Credential(Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY);
+
+ ArgumentCaptor<IGetCredentialCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IGetCredentialCallback.class);
+ ArgumentCaptor<GetCredentialResponse> responseCaptor = ArgumentCaptor.forClass(
+ GetCredentialResponse.class);
+
+ OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeGetCredential(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.getCredential(mGetRequest, mMockActivity, null, mExecutor, callback);
+ verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
+
+ callbackCaptor.getValue().onResponse(new GetCredentialResponse(cred));
+ verify(callback).onResult(responseCaptor.capture());
+
+ assertThat(responseCaptor.getValue().getCredential().getType()).isEqualTo(cred.getType());
+ }
+
+ @Test
+ public void testCreateCredential_nullRequest() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.createCredential(null, mMockActivity, null, mExecutor,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testCreateCredential_nullActivity() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.createCredential(mCreateRequest, null, null, mExecutor,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testCreateCredential_nullExecutor() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, null,
+ result -> {
+ }));
+ }
+
+ @Test
+ public void testCreateCredential_nullCallback() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.createCredential(mCreateRequest, mMockActivity, null,
+ mExecutor, null));
+ }
+
+ @Test
+ public void testCreateCredential_alreadyCancelled() throws RemoteException {
+ final CancellationSignal cancellation = new CancellationSignal();
+ cancellation.cancel();
+
+ mCredentialManager.createCredential(mCreateRequest, mMockActivity, cancellation, mExecutor,
+ result -> {
+ });
+
+ verify(mMockCredentialManagerService, never()).executeCreateCredential(any(), any(), any());
+ }
+
+ @Test
+ public void testCreateCredential_cancel() throws RemoteException {
+ final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
+ final CancellationSignal cancellation = new CancellationSignal();
+
+ OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeCreateCredential(any(), any(), any())).thenReturn(
+ serviceSignal);
+
+ mCredentialManager.createCredential(mCreateRequest, mMockActivity, cancellation, mExecutor,
+ callback);
+
+ verify(mMockCredentialManagerService).executeCreateCredential(any(), any(),
+ eq(mPackageName));
+
+ cancellation.cancel();
+ verify(serviceSignal).cancel();
+ }
+
+ @Test
+ public void testCreateCredential_failed() throws RemoteException {
+ ArgumentCaptor<ICreateCredentialCallback> callbackCaptor = ArgumentCaptor.forClass(
+ ICreateCredentialCallback.class);
+ ArgumentCaptor<CreateCredentialException> errorCaptor = ArgumentCaptor.forClass(
+ CreateCredentialException.class);
+
+ OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeCreateCredential(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, mExecutor,
+ callback);
+ verify(mMockCredentialManagerService).executeCreateCredential(any(), any(),
+ eq(mPackageName));
+
+ callbackCaptor.getValue().onError(CreateCredentialException.TYPE_UNKNOWN, "unknown error");
+ verify(callback).onError(errorCaptor.capture());
+
+ assertThat(errorCaptor.getValue().getType()).isEqualTo(
+ CreateCredentialException.TYPE_UNKNOWN);
+ }
+
+ @Test
+ public void testCreateCredential_success() throws RemoteException {
+ final Bundle responseData = new Bundle();
+ responseData.putString("foo", "bar");
+
+ ArgumentCaptor<ICreateCredentialCallback> callbackCaptor = ArgumentCaptor.forClass(
+ ICreateCredentialCallback.class);
+ ArgumentCaptor<CreateCredentialResponse> responseCaptor = ArgumentCaptor.forClass(
+ CreateCredentialResponse.class);
+
+ OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback = mock(
+ OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.executeCreateCredential(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, mExecutor,
+ callback);
+ verify(mMockCredentialManagerService).executeCreateCredential(any(), any(),
+ eq(mPackageName));
+
+ callbackCaptor.getValue().onResponse(new CreateCredentialResponse(responseData));
+ verify(callback).onResult(responseCaptor.capture());
+
+ assertBundleEquals(responseCaptor.getValue().getData(), responseData);
+ }
+
+ @Test
+ public void testClearCredentialState_nullRequest() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.clearCredentialState(null, null, mExecutor, result -> {
+ }));
+ }
+
+ @Test
+ public void testClearCredentialState_nullExecutor() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.clearCredentialState(mClearRequest, null, null, result -> {
+ }));
+ }
+
+ @Test
+ public void testClearCredentialState_nullCallback() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor,
+ null));
+ }
+
+ @Test
+ public void testClearCredential_alreadyCancelled() throws RemoteException {
+ final CancellationSignal cancellation = new CancellationSignal();
+ cancellation.cancel();
+
+ mCredentialManager.clearCredentialState(mClearRequest, cancellation, mExecutor, result -> {
+ });
+
+ verify(mMockCredentialManagerService, never()).clearCredentialState(any(), any(), any());
+ }
+
+ @Test
+ public void testClearCredential_cancel() throws RemoteException {
+ final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
+ final CancellationSignal cancellation = new CancellationSignal();
+
+ OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.clearCredentialState(any(), any(), any())).thenReturn(
+ serviceSignal);
+
+ mCredentialManager.clearCredentialState(mClearRequest, cancellation, mExecutor, callback);
+
+ verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName));
+
+ cancellation.cancel();
+ verify(serviceSignal).cancel();
+ }
+
+ @Test
+ public void testClearCredential_failed() throws RemoteException {
+ ArgumentCaptor<IClearCredentialStateCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IClearCredentialStateCallback.class);
+ ArgumentCaptor<ClearCredentialStateException> errorCaptor = ArgumentCaptor.forClass(
+ ClearCredentialStateException.class);
+
+ OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.clearCredentialState(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor, callback);
+ verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName));
+
+ callbackCaptor.getValue().onError(ClearCredentialStateException.TYPE_UNKNOWN,
+ "unknown error");
+ verify(callback).onError(errorCaptor.capture());
+
+ assertThat(errorCaptor.getValue().getType()).isEqualTo(
+ ClearCredentialStateException.TYPE_UNKNOWN);
+ }
+
+ @Test
+ public void testClearCredential_success() throws RemoteException {
+ ArgumentCaptor<IClearCredentialStateCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IClearCredentialStateCallback.class);
+
+ OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.clearCredentialState(any(), callbackCaptor.capture(),
+ any())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor, callback);
+ verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName));
+
+ callbackCaptor.getValue().onSuccess();
+ verify(callback).onResult(any());
+ }
+
+ @Test
+ public void testListEnabledProviders_nullExecutor() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.listEnabledProviders(null, null, result -> {
+ }));
+
+ }
+
+ @Test
+ public void testListEnabledProviders_nullCallback() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.listEnabledProviders(null, mExecutor, null));
+
+ }
+
+ @Test
+ public void testListEnabledProviders_alreadyCancelled() throws RemoteException {
+ final CancellationSignal cancellation = new CancellationSignal();
+ cancellation.cancel();
+
+ mCredentialManager.listEnabledProviders(cancellation, mExecutor, result -> {
+ });
+
+ verify(mMockCredentialManagerService, never()).listEnabledProviders(any());
+ }
+
+ @Test
+ public void testListEnabledProviders_cancel() throws RemoteException {
+ final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
+ final CancellationSignal cancellation = new CancellationSignal();
+
+ OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException> callback =
+ mock(OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.listEnabledProviders(any())).thenReturn(serviceSignal);
+
+ mCredentialManager.listEnabledProviders(cancellation, mExecutor, callback);
+
+ verify(mMockCredentialManagerService).listEnabledProviders(any());
+
+ cancellation.cancel();
+ verify(serviceSignal).cancel();
+ }
+
+ @Test
+ public void testListEnabledProviders_failed() throws RemoteException {
+ ArgumentCaptor<IListEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IListEnabledProvidersCallback.class);
+ ArgumentCaptor<ListEnabledProvidersException> errorCaptor = ArgumentCaptor.forClass(
+ ListEnabledProvidersException.class);
+
+ OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException> callback =
+ mock(OutcomeReceiver.class);
+
+ when(mMockCredentialManagerService.listEnabledProviders(
+ callbackCaptor.capture())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.listEnabledProviders(null, mExecutor, callback);
+ verify(mMockCredentialManagerService).listEnabledProviders(any());
+
+ final String errorType = "type";
+ callbackCaptor.getValue().onError("type", "unknown error");
+ verify(callback).onError(errorCaptor.capture());
+
+ assertThat(errorCaptor.getValue().getType()).isEqualTo(errorType);
+ }
+
+ @Test
+ public void testListEnabledProviders_success() throws RemoteException {
+ ListEnabledProvidersResponse response = ListEnabledProvidersResponse.create(
+ List.of("foo", "bar", "baz"));
+
+ OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException> callback =
+ mock(OutcomeReceiver.class);
+
+ ArgumentCaptor<IListEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass(
+ IListEnabledProvidersCallback.class);
+ ArgumentCaptor<ListEnabledProvidersResponse> responseCaptor = ArgumentCaptor.forClass(
+ ListEnabledProvidersResponse.class);
+
+ when(mMockCredentialManagerService.listEnabledProviders(
+ callbackCaptor.capture())).thenReturn(mock(ICancellationSignal.class));
+ mCredentialManager.listEnabledProviders(null, mExecutor, callback);
+
+ verify(mMockCredentialManagerService).listEnabledProviders(any());
+
+ callbackCaptor.getValue().onResponse(response);
+
+ verify(callback).onResult(responseCaptor.capture());
+ assertThat(responseCaptor.getValue().getProviderComponentNames()).containsExactlyElementsIn(
+ response.getProviderComponentNames());
+ }
+
+ @Test
+ public void testSetEnabledProviders_nullProviders() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.setEnabledProviders(null, 0, mExecutor, response -> {
+ }));
+
+ }
+
+ @Test
+ public void testSetEnabledProviders_nullExecutor() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.setEnabledProviders(List.of("foo"), 0, null, response -> {
+ }));
+
+ }
+
+ @Test
+ public void testSetEnabledProviders_nullCallback() {
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.setEnabledProviders(List.of("foo"), 0, mExecutor, null));
+
+ }
+
+ @Test
+ public void testSetEnabledProviders_failed() throws RemoteException {
+ OutcomeReceiver<Void, SetEnabledProvidersException> callback = mock(OutcomeReceiver.class);
+
+ ArgumentCaptor<ISetEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass(
+ ISetEnabledProvidersCallback.class);
+ ArgumentCaptor<SetEnabledProvidersException> errorCaptor = ArgumentCaptor.forClass(
+ SetEnabledProvidersException.class);
+
+ final List<String> providers = List.of("foo", "bar");
+ final int userId = 0;
+ mCredentialManager.setEnabledProviders(providers, userId, mExecutor, callback);
+ verify(mMockCredentialManagerService).setEnabledProviders(eq(providers), eq(0),
+ callbackCaptor.capture());
+
+ final String errorType = "unknown";
+ final String errorMessage = "Unknown error";
+ callbackCaptor.getValue().onError(errorType, errorMessage);
+ verify(callback).onError(errorCaptor.capture());
+
+ assertThat(errorCaptor.getValue().getType()).isEqualTo(errorType);
+ assertThat(errorCaptor.getValue().getMessage()).isEqualTo(errorMessage);
+ }
+
+ @Test
+ public void testSetEnabledProviders_success() throws RemoteException {
+ OutcomeReceiver<Void, SetEnabledProvidersException> callback = mock(OutcomeReceiver.class);
+
+ ArgumentCaptor<ISetEnabledProvidersCallback> callbackCaptor = ArgumentCaptor.forClass(
+ ISetEnabledProvidersCallback.class);
+
+ final List<String> providers = List.of("foo", "bar");
+ final int userId = 0;
+ mCredentialManager.setEnabledProviders(providers, userId, mExecutor, callback);
+
+ verify(mMockCredentialManagerService).setEnabledProviders(eq(providers), eq(0),
+ callbackCaptor.capture());
+
+ callbackCaptor.getValue().onResponse();
+ verify(callback).onResult(any());
+ }
+
+ @Test
+ public void testRegisterCredentialDescription_nullRequest() {
+ assumeTrue(CredentialManager.isCredentialDescriptionApiEnabled());
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.registerCredentialDescription(null));
+ }
+
+ @Test
+ public void testRegisterCredentialDescription_success() throws RemoteException {
+ assumeTrue(CredentialManager.isCredentialDescriptionApiEnabled());
+
+ mCredentialManager.registerCredentialDescription(mRegisterRequest);
+ verify(mMockCredentialManagerService).registerCredentialDescription(same(mRegisterRequest),
+ eq(mPackageName));
+ }
+
+ @Test
+ public void testUnregisterCredentialDescription_nullRequest() {
+ assumeTrue(CredentialManager.isCredentialDescriptionApiEnabled());
+
+ assertThrows(NullPointerException.class,
+ () -> mCredentialManager.unregisterCredentialDescription(null));
+ }
+
+ @Test
+ public void testUnregisterCredentialDescription_success() throws RemoteException {
+ assumeTrue(CredentialManager.isCredentialDescriptionApiEnabled());
+
+ mCredentialManager.unregisterCredentialDescription(mUnregisterRequest);
+ verify(mMockCredentialManagerService).unregisterCredentialDescription(
+ same(mUnregisterRequest), eq(mPackageName));
+ }
+}
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index b1abc2a1..a39dd08 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -2175,23 +2175,26 @@
public static final @NonNull Parcelable.Creator<Bitmap> CREATOR
= new Parcelable.Creator<Bitmap>() {
- /**
- * Rebuilds a bitmap previously stored with writeToParcel().
- *
- * @param p Parcel object to read the bitmap from
- * @return a new bitmap created from the data in the parcel
- */
- public Bitmap createFromParcel(Parcel p) {
- Bitmap bm = nativeCreateFromParcel(p);
- if (bm == null) {
- throw new RuntimeException("Failed to unparcel Bitmap");
- }
- return bm;
- }
- public Bitmap[] newArray(int size) {
- return new Bitmap[size];
- }
- };
+ /**
+ * Rebuilds a bitmap previously stored with writeToParcel().
+ *
+ * @param p Parcel object to read the bitmap from
+ * @return a new bitmap created from the data in the parcel
+ */
+ public Bitmap createFromParcel(Parcel p) {
+ Bitmap bm = nativeCreateFromParcel(p);
+ if (bm == null) {
+ throw new RuntimeException("Failed to unparcel Bitmap");
+ }
+ if (p.readBoolean()) {
+ bm.setGainmap(p.readTypedObject(Gainmap.CREATOR));
+ }
+ return bm;
+ }
+ public Bitmap[] newArray(int size) {
+ return new Bitmap[size];
+ }
+ };
/**
* No special parcel contents.
@@ -2215,6 +2218,12 @@
if (!nativeWriteToParcel(mNativePtr, mDensity, p)) {
throw new RuntimeException("native writeToParcel failed");
}
+ if (hasGainmap()) {
+ p.writeBoolean(true);
+ p.writeTypedObject(mGainmap, flags);
+ } else {
+ p.writeBoolean(false);
+ }
}
/**
diff --git a/graphics/java/android/graphics/Gainmap.java b/graphics/java/android/graphics/Gainmap.java
index 53f23c0..470a06c 100644
--- a/graphics/java/android/graphics/Gainmap.java
+++ b/graphics/java/android/graphics/Gainmap.java
@@ -18,6 +18,8 @@
import android.annotation.FloatRange;
import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
import libcore.util.NativeAllocationRegistry;
@@ -76,7 +78,7 @@
*
* In the above math, log() is a natural logarithm and exp() is natural exponentiation.
*/
-public final class Gainmap {
+public final class Gainmap implements Parcelable {
// Use a Holder to allow static initialization of Gainmap in the boot image.
private static class NoImagePreloadHolder {
@@ -284,6 +286,50 @@
return nGetDisplayRatioSdr(mNativePtr);
}
+ /**
+ * No special parcel contents.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Write the gainmap to the parcel.
+ *
+ * @param dest Parcel object to write the gainmap data into
+ * @param flags Additional flags about how the object should be written.
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ if (mNativePtr == 0) {
+ throw new IllegalStateException("Cannot be written to a parcel");
+ }
+ dest.writeTypedObject(mGainmapContents, flags);
+ // write gainmapinfo into parcel
+ nWriteGainmapToParcel(mNativePtr, dest);
+ }
+
+ public static final @NonNull Parcelable.Creator<Gainmap> CREATOR =
+ new Parcelable.Creator<Gainmap>() {
+ /**
+ * Rebuilds a gainmap previously stored with writeToParcel().
+ *
+ * @param in Parcel object to read the gainmap from
+ * @return a new gainmap created from the data in the parcel
+ */
+ public Gainmap createFromParcel(Parcel in) {
+ Gainmap gm = new Gainmap(in.readTypedObject(Bitmap.CREATOR));
+ // read gainmapinfo from parcel
+ nReadGainmapFromParcel(gm.mNativePtr, in);
+ return gm;
+ }
+
+ public Gainmap[] newArray(int size) {
+ return new Gainmap[size];
+ }
+ };
+
private static native long nGetFinalizer();
private static native long nCreateEmpty();
@@ -309,4 +355,6 @@
private static native void nSetDisplayRatioSdr(long ptr, float min);
private static native float nGetDisplayRatioSdr(long ptr);
+ private static native void nWriteGainmapToParcel(long ptr, Parcel dest);
+ private static native void nReadGainmapFromParcel(long ptr, Parcel src);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index bc81710..c9c0e40 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -41,6 +41,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArraySet;
+import android.util.Pair;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.DisplayAreaInfo;
@@ -363,10 +364,10 @@
}
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "handle shell transition request: %s", request);
- WindowContainerTransaction wct = mTransitions.dispatchRequest(transition, request, this);
- if (wct == null) {
- wct = new WindowContainerTransaction();
- }
+ Pair<Transitions.TransitionHandler, WindowContainerTransaction> subHandler =
+ mTransitions.dispatchRequest(transition, request, this);
+ WindowContainerTransaction wct = subHandler != null
+ ? subHandler.second : new WindowContainerTransaction();
bringDesktopAppsToFront(wct);
wct.reorder(request.getTriggerTask().token, true /* onTop */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index a2d7bc4..c2da705 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -17,6 +17,7 @@
package com.android.wm.shell.transition;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -28,11 +29,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IBinder;
+import android.util.Pair;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
+import android.window.WindowContainerTransactionCallback;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.pip.PipTransitionController;
@@ -61,6 +64,9 @@
/** Both the display and split-state (enter/exit) is changing */
static final int TYPE_DISPLAY_AND_SPLIT_CHANGE = 2;
+ /** Pip was entered while handling an intent with its own remoteTransition. */
+ static final int TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE = 3;
+
/** The default animation for this mixed transition. */
static final int ANIM_TYPE_DEFAULT = 0;
@@ -85,6 +91,23 @@
mType = type;
mTransition = transition;
}
+
+ void joinFinishArgs(WindowContainerTransaction wct,
+ WindowContainerTransactionCallback wctCB) {
+ if (wctCB != null) {
+ // Technically can probably support 1, but don't want to encourage CB usage since
+ // it creates instabliity, so just throw.
+ throw new IllegalArgumentException("Can't mix transitions that require finish"
+ + " sync callback");
+ }
+ if (wct != null) {
+ if (mFinishWCT == null) {
+ mFinishWCT = wct;
+ } else {
+ mFinishWCT.merge(wct, true /* transfer */);
+ }
+ }
+ }
}
private final ArrayList<MixedTransition> mActiveTransitions = new ArrayList<>();
@@ -125,6 +148,25 @@
mPipHandler.augmentRequest(transition, request, out);
mSplitHandler.addEnterOrExitIfNeeded(request, out);
return out;
+ } else if (request.getRemoteTransition() != null
+ && Transitions.isOpeningType(request.getType())
+ && (request.getTriggerTask() == null
+ || (request.getTriggerTask().topActivityType != ACTIVITY_TYPE_HOME
+ && request.getTriggerTask().topActivityType != ACTIVITY_TYPE_RECENTS))) {
+ // Only select transitions with an intent-provided remote-animation because that will
+ // usually grab priority and often won't handle PiP. If there isn't an intent-provided
+ // remote, then the transition will be dispatched normally and the PipHandler will
+ // pick it up.
+ Pair<Transitions.TransitionHandler, WindowContainerTransaction> handler =
+ mPlayer.dispatchRequest(transition, request, this);
+ if (handler == null) {
+ return null;
+ }
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE, transition);
+ mixed.mLeftoversHandler = handler.first;
+ mActiveTransitions.add(mixed);
+ return handler.second;
}
return null;
}
@@ -169,6 +211,9 @@
finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE) {
return false;
+ } else if (mixed.mType == MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) {
+ return animateOpenIntentWithRemoteAndPip(mixed, info, startTransaction,
+ finishTransaction, finishCallback);
} else {
mActiveTransitions.remove(mixed);
throw new IllegalStateException("Starting mixed animation without a known mixed type? "
@@ -176,6 +221,59 @@
}
}
+ private boolean animateOpenIntentWithRemoteAndPip(@NonNull MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ TransitionInfo.Change pipChange = null;
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ TransitionInfo.Change change = info.getChanges().get(i);
+ if (mPipHandler.isEnteringPip(change, info.getType())) {
+ if (pipChange != null) {
+ throw new IllegalStateException("More than 1 pip-entering changes in one"
+ + " transition? " + info);
+ }
+ pipChange = change;
+ info.getChanges().remove(i);
+ }
+ }
+ if (pipChange == null) {
+ if (mixed.mLeftoversHandler != null) {
+ return mixed.mLeftoversHandler.startAnimation(mixed.mTransition, info,
+ startTransaction, finishTransaction, finishCallback);
+ }
+ return false;
+ }
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Splitting PIP into a separate"
+ + " animation because remote-animation likely doesn't support it");
+ mixed.mFinishCallback = finishCallback;
+ Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ --mixed.mInFlightSubAnimations;
+ mixed.joinFinishArgs(wct, wctCB);
+ if (mixed.mInFlightSubAnimations > 0) return;
+ mActiveTransitions.remove(mixed);
+ mixed.mFinishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB);
+ };
+ // Split the transition into 2 parts: the pip part and the rest.
+ mixed.mInFlightSubAnimations = 2;
+ // make a new startTransaction because pip's startEnterAnimation "consumes" it so
+ // we need a separate one to send over to launcher.
+ SurfaceControl.Transaction otherStartT = new SurfaceControl.Transaction();
+
+ mPipHandler.startEnterAnimation(pipChange, otherStartT, finishTransaction, finishCB);
+
+ // Dispatch the rest of the transition normally.
+ if (mixed.mLeftoversHandler != null
+ && mixed.mLeftoversHandler.startAnimation(mixed.mTransition, info,
+ startTransaction, finishTransaction, finishCB)) {
+ return true;
+ }
+ mixed.mLeftoversHandler = mPlayer.dispatchTransition(mixed.mTransition, info,
+ startTransaction, finishTransaction, finishCB, this);
+ return true;
+ }
+
private boolean animateEnterPipFromSplit(@NonNull final MixedTransition mixed,
@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@@ -211,12 +309,13 @@
mixed.mFinishCallback = finishCallback;
Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
--mixed.mInFlightSubAnimations;
+ mixed.joinFinishArgs(wct, wctCB);
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
if (isGoingHome) {
mSplitHandler.onTransitionAnimationComplete();
}
- mixed.mFinishCallback.onTransitionFinished(wct, wctCB);
+ mixed.mFinishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB);
};
if (isGoingHome) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animation is actually mixed "
@@ -317,17 +416,7 @@
Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
--mixed.mInFlightSubAnimations;
- if (wctCB != null) {
- throw new IllegalArgumentException("Can't mix transitions that require finish"
- + " sync callback");
- }
- if (wct != null) {
- if (mixed.mFinishWCT == null) {
- mixed.mFinishWCT = wct;
- } else {
- mixed.mFinishWCT.merge(wct, true /* transfer */);
- }
- }
+ mixed.joinFinishArgs(wct, wctCB);
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
mixed.mFinishCallback.onTransitionFinished(mixed.mFinishWCT, null /* wctCB */);
@@ -342,8 +431,7 @@
// Note: at this point, startT has probably already been applied, so we are basically
// giving splitHandler an empty startT. This is currently OK because display-change will
// grab a screenshot and paste it on top anyways.
- mSplitHandler.startPendingAnimation(
- transition, everythingElse, startT, finishT, finishCB);
+ mSplitHandler.startPendingAnimation(transition, everythingElse, startT, finishT, finishCB);
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 75d1939..0826fe2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -47,6 +47,7 @@
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
+import android.util.Pair;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.ITransitionPlayer;
@@ -627,13 +628,14 @@
* Gives every handler (in order) a chance to handle request until one consumes the transition.
* @return the WindowContainerTransaction given by the handler which consumed the transition.
*/
- public WindowContainerTransaction dispatchRequest(@NonNull IBinder transition,
- @NonNull TransitionRequestInfo request, @Nullable TransitionHandler skip) {
+ public Pair<TransitionHandler, WindowContainerTransaction> dispatchRequest(
+ @NonNull IBinder transition, @NonNull TransitionRequestInfo request,
+ @Nullable TransitionHandler skip) {
for (int i = mHandlers.size() - 1; i >= 0; --i) {
if (mHandlers.get(i) == skip) continue;
WindowContainerTransaction wct = mHandlers.get(i).handleRequest(transition, request);
if (wct != null) {
- return wct;
+ return new Pair<>(mHandlers.get(i), wct);
}
}
return null;
@@ -698,9 +700,9 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
"Transition animation finished (abort=%b), notifying core %s", abort, transition);
if (active.mStartT != null) {
- // Applied by now, so close immediately. Do not set to null yet, though, since nullness
- // is used later to disambiguate malformed transitions.
- active.mStartT.close();
+ // Applied by now, so clear immediately to remove any references. Do not set to null
+ // yet, though, since nullness is used later to disambiguate malformed transitions.
+ active.mStartT.clear();
}
// Merge all relevant transactions together
SurfaceControl.Transaction fullFinish = active.mFinishT;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 44e4a31..de5f2f4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -250,25 +250,30 @@
@Override
public boolean onTouch(View v, MotionEvent e) {
- boolean isDrag = false;
final int id = v.getId();
if (id != R.id.caption_handle && id != R.id.desktop_mode_caption) {
return false;
}
- if (id == R.id.caption_handle) {
- isDrag = mDragDetector.onMotionEvent(e);
+ switch (e.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mDragDetector.onMotionEvent(e);
+ final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
+ if (taskInfo.isFocused) {
+ return mDragDetector.isDragEvent();
+ }
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.reorder(mTaskToken, true /* onTop */);
+ mSyncQueue.queue(wct);
+ return false;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ boolean res = mDragDetector.isDragEvent();
+ mDragDetector.onMotionEvent(e);
+ return res;
+ default:
+ mDragDetector.onMotionEvent(e);
+ return mDragDetector.isDragEvent();
}
- if (e.getAction() != MotionEvent.ACTION_DOWN) {
- return isDrag;
- }
- final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
- if (taskInfo.isFocused) {
- return isDrag;
- }
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reorder(mTaskToken, true /* onTop */);
- mSyncQueue.queue(wct);
- return true;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index 4fac843..cf1850b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -94,6 +94,10 @@
mTouchSlop = touchSlop;
}
+ boolean isDragEvent() {
+ return mIsDragEvent;
+ }
+
private void resetState() {
mIsDragEvent = false;
mInputDownPoint.set(0, 0);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 03d89cc..d63b3e7 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -364,6 +364,7 @@
"jni/PathMeasure.cpp",
"jni/Picture.cpp",
"jni/Region.cpp",
+ "jni/ScopedParcel.cpp",
"jni/Shader.cpp",
"jni/RenderEffect.cpp",
"jni/Typeface.cpp",
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index e71a2a5..3f9c4bd 100644
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -10,6 +10,7 @@
#include "Gainmap.h"
#include "GraphicsJNI.h"
#include "HardwareBufferHelpers.h"
+#include "ScopedParcel.h"
#include "SkBitmap.h"
#include "SkBlendMode.h"
#include "SkCanvas.h"
@@ -27,12 +28,7 @@
#ifdef __ANDROID__ // Layoutlib does not support graphic buffer, parcel or render thread
#include <android-base/unique_fd.h>
-#include <android/binder_parcel.h>
-#include <android/binder_parcel_jni.h>
-#include <android/binder_parcel_platform.h>
-#include <cutils/ashmem.h>
#include <renderthread/RenderProxy.h>
-#include <sys/mman.h>
#endif
#include <inttypes.h>
@@ -616,91 +612,7 @@
///////////////////////////////////////////////////////////////////////////////
// TODO: Move somewhere else
-#ifdef __ANDROID__ // Layoutlib does not support parcel
-
-class ScopedParcel {
-public:
- explicit ScopedParcel(JNIEnv* env, jobject parcel) {
- mParcel = AParcel_fromJavaParcel(env, parcel);
- }
-
- ~ScopedParcel() { AParcel_delete(mParcel); }
-
- int32_t readInt32() {
- int32_t temp = 0;
- // TODO: This behavior-matches what android::Parcel does
- // but this should probably be better
- if (AParcel_readInt32(mParcel, &temp) != STATUS_OK) {
- temp = 0;
- }
- return temp;
- }
-
- uint32_t readUint32() {
- uint32_t temp = 0;
- // TODO: This behavior-matches what android::Parcel does
- // but this should probably be better
- if (AParcel_readUint32(mParcel, &temp) != STATUS_OK) {
- temp = 0;
- }
- return temp;
- }
-
- void writeInt32(int32_t value) { AParcel_writeInt32(mParcel, value); }
-
- void writeUint32(uint32_t value) { AParcel_writeUint32(mParcel, value); }
-
- bool allowFds() const { return AParcel_getAllowFds(mParcel); }
-
- std::optional<sk_sp<SkData>> readData() {
- struct Data {
- void* ptr = nullptr;
- size_t size = 0;
- } data;
- auto error = AParcel_readByteArray(mParcel, &data,
- [](void* arrayData, int32_t length,
- int8_t** outBuffer) -> bool {
- Data* data = reinterpret_cast<Data*>(arrayData);
- if (length > 0) {
- data->ptr = sk_malloc_canfail(length);
- if (!data->ptr) {
- return false;
- }
- *outBuffer =
- reinterpret_cast<int8_t*>(data->ptr);
- data->size = length;
- }
- return true;
- });
- if (error != STATUS_OK || data.size <= 0) {
- sk_free(data.ptr);
- return std::nullopt;
- } else {
- return SkData::MakeFromMalloc(data.ptr, data.size);
- }
- }
-
- void writeData(const std::optional<sk_sp<SkData>>& optData) {
- if (optData) {
- const auto& data = *optData;
- AParcel_writeByteArray(mParcel, reinterpret_cast<const int8_t*>(data->data()),
- data->size());
- } else {
- AParcel_writeByteArray(mParcel, nullptr, -1);
- }
- }
-
- AParcel* get() { return mParcel; }
-
-private:
- AParcel* mParcel;
-};
-
-enum class BlobType : int32_t {
- IN_PLACE,
- ASHMEM,
-};
-
+#ifdef __ANDROID__ // Layoutlib does not support parcel
#define ON_ERROR_RETURN(X) \
if ((error = (X)) != STATUS_OK) return error
diff --git a/libs/hwui/jni/Gainmap.cpp b/libs/hwui/jni/Gainmap.cpp
index 9cd3fb0..0f8a85d 100644
--- a/libs/hwui/jni/Gainmap.cpp
+++ b/libs/hwui/jni/Gainmap.cpp
@@ -16,8 +16,13 @@
#include <Gainmap.h>
+#ifdef __ANDROID__
+#include <binder/Parcel.h>
+#endif
+
#include "Bitmap.h"
#include "GraphicsJNI.h"
+#include "ScopedParcel.h"
#include "graphics_jni_helpers.h"
namespace android {
@@ -154,6 +159,81 @@
return fromJava(gainmapPtr)->info.fDisplayRatioSdr;
}
+// ----------------------------------------------------------------------------
+// Serialization
+// ----------------------------------------------------------------------------
+
+static void Gainmap_writeToParcel(JNIEnv* env, jobject, jlong nativeObject, jobject parcel) {
+#ifdef __ANDROID__ // Layoutlib does not support parcel
+ if (parcel == NULL) {
+ ALOGD("write null parcel\n");
+ return;
+ }
+ ScopedParcel p(env, parcel);
+ SkGainmapInfo info = fromJava(nativeObject)->info;
+ // write gainmap to parcel
+ // ratio min
+ p.writeFloat(info.fGainmapRatioMin.fR);
+ p.writeFloat(info.fGainmapRatioMin.fG);
+ p.writeFloat(info.fGainmapRatioMin.fB);
+ // ratio max
+ p.writeFloat(info.fGainmapRatioMax.fR);
+ p.writeFloat(info.fGainmapRatioMax.fG);
+ p.writeFloat(info.fGainmapRatioMax.fB);
+ // gamma
+ p.writeFloat(info.fGainmapGamma.fR);
+ p.writeFloat(info.fGainmapGamma.fG);
+ p.writeFloat(info.fGainmapGamma.fB);
+ // epsilonsdr
+ p.writeFloat(info.fEpsilonSdr.fR);
+ p.writeFloat(info.fEpsilonSdr.fG);
+ p.writeFloat(info.fEpsilonSdr.fB);
+ // epsilonhdr
+ p.writeFloat(info.fEpsilonHdr.fR);
+ p.writeFloat(info.fEpsilonHdr.fG);
+ p.writeFloat(info.fEpsilonHdr.fB);
+ // display ratio sdr
+ p.writeFloat(info.fDisplayRatioSdr);
+ // display ratio hdr
+ p.writeFloat(info.fDisplayRatioHdr);
+ // base image type
+ p.writeInt32(static_cast<int32_t>(info.fBaseImageType));
+ // type
+ p.writeInt32(static_cast<int32_t>(info.fType));
+#else
+ doThrowRE(env, "Cannot use parcels outside of Android!");
+#endif
+}
+
+static void Gainmap_readFromParcel(JNIEnv* env, jobject, jlong nativeObject, jobject parcel) {
+#ifdef __ANDROID__ // Layoutlib does not support parcel
+ if (parcel == NULL) {
+ jniThrowNullPointerException(env, "parcel cannot be null");
+ return;
+ }
+ ScopedParcel p(env, parcel);
+
+ SkGainmapInfo info;
+ info.fGainmapRatioMin = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
+ info.fGainmapRatioMax = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
+ info.fGainmapGamma = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
+ info.fEpsilonSdr = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
+ info.fEpsilonHdr = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
+ info.fDisplayRatioSdr = p.readFloat();
+ info.fDisplayRatioHdr = p.readFloat();
+ info.fBaseImageType = static_cast<SkGainmapInfo::BaseImageType>(p.readInt32());
+ info.fType = static_cast<SkGainmapInfo::Type>(p.readInt32());
+
+ fromJava(nativeObject)->info = info;
+#else
+ jniThrowRuntimeException(env, "Cannot use parcels outside of Android");
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
static const JNINativeMethod gGainmapMethods[] = {
{"nGetFinalizer", "()J", (void*)Gainmap_getNativeFinalizer},
{"nCreateEmpty", "()J", (void*)Gainmap_createEmpty},
@@ -172,6 +252,8 @@
{"nGetDisplayRatioHdr", "(J)F", (void*)Gainmap_getDisplayRatioHdr},
{"nSetDisplayRatioSdr", "(JF)V", (void*)Gainmap_setDisplayRatioSdr},
{"nGetDisplayRatioSdr", "(J)F", (void*)Gainmap_getDisplayRatioSdr},
+ {"nWriteGainmapToParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_writeToParcel},
+ {"nReadGainmapFromParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_readFromParcel},
};
int register_android_graphics_Gainmap(JNIEnv* env) {
diff --git a/libs/hwui/jni/ScopedParcel.cpp b/libs/hwui/jni/ScopedParcel.cpp
new file mode 100644
index 0000000..b0f5423
--- /dev/null
+++ b/libs/hwui/jni/ScopedParcel.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ScopedParcel.h"
+
+#ifdef __ANDROID__ // Layoutlib does not support parcel
+
+using namespace android;
+
+int32_t ScopedParcel::readInt32() {
+ int32_t temp = 0;
+ // TODO: This behavior-matches what android::Parcel does
+ // but this should probably be better
+ if (AParcel_readInt32(mParcel, &temp) != STATUS_OK) {
+ temp = 0;
+ }
+ return temp;
+}
+
+uint32_t ScopedParcel::readUint32() {
+ uint32_t temp = 0;
+ // TODO: This behavior-matches what android::Parcel does
+ // but this should probably be better
+ if (AParcel_readUint32(mParcel, &temp) != STATUS_OK) {
+ temp = 0;
+ }
+ return temp;
+}
+
+float ScopedParcel::readFloat() {
+ float temp = 0.;
+ if (AParcel_readFloat(mParcel, &temp) != STATUS_OK) {
+ temp = 0.;
+ }
+ return temp;
+}
+
+std::optional<sk_sp<SkData>> ScopedParcel::readData() {
+ struct Data {
+ void* ptr = nullptr;
+ size_t size = 0;
+ } data;
+ auto error = AParcel_readByteArray(
+ mParcel, &data, [](void* arrayData, int32_t length, int8_t** outBuffer) -> bool {
+ Data* data = reinterpret_cast<Data*>(arrayData);
+ if (length > 0) {
+ data->ptr = sk_malloc_canfail(length);
+ if (!data->ptr) {
+ return false;
+ }
+ *outBuffer = reinterpret_cast<int8_t*>(data->ptr);
+ data->size = length;
+ }
+ return true;
+ });
+ if (error != STATUS_OK || data.size <= 0) {
+ sk_free(data.ptr);
+ return std::nullopt;
+ } else {
+ return SkData::MakeFromMalloc(data.ptr, data.size);
+ }
+}
+
+void ScopedParcel::writeData(const std::optional<sk_sp<SkData>>& optData) {
+ if (optData) {
+ const auto& data = *optData;
+ AParcel_writeByteArray(mParcel, reinterpret_cast<const int8_t*>(data->data()),
+ data->size());
+ } else {
+ AParcel_writeByteArray(mParcel, nullptr, -1);
+ }
+}
+#endif // __ANDROID__ // Layoutlib does not support parcel
diff --git a/libs/hwui/jni/ScopedParcel.h b/libs/hwui/jni/ScopedParcel.h
new file mode 100644
index 0000000..fd8d6a2
--- /dev/null
+++ b/libs/hwui/jni/ScopedParcel.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "SkData.h"
+
+#ifdef __ANDROID__ // Layoutlib does not support parcel
+#include <android-base/unique_fd.h>
+#include <android/binder_parcel.h>
+#include <android/binder_parcel_jni.h>
+#include <android/binder_parcel_platform.h>
+#include <cutils/ashmem.h>
+#include <renderthread/RenderProxy.h>
+
+class ScopedParcel {
+public:
+ explicit ScopedParcel(JNIEnv* env, jobject parcel) {
+ mParcel = AParcel_fromJavaParcel(env, parcel);
+ }
+
+ ~ScopedParcel() { AParcel_delete(mParcel); }
+
+ int32_t readInt32();
+
+ uint32_t readUint32();
+
+ float readFloat();
+
+ void writeInt32(int32_t value) { AParcel_writeInt32(mParcel, value); }
+
+ void writeUint32(uint32_t value) { AParcel_writeUint32(mParcel, value); }
+
+ void writeFloat(float value) { AParcel_writeFloat(mParcel, value); }
+
+ bool allowFds() const { return AParcel_getAllowFds(mParcel); }
+
+ std::optional<sk_sp<SkData>> readData();
+
+ void writeData(const std::optional<sk_sp<SkData>>& optData);
+
+ AParcel* get() { return mParcel; }
+
+private:
+ AParcel* mParcel;
+};
+
+enum class BlobType : int32_t {
+ IN_PLACE,
+ ASHMEM,
+};
+
+#endif // __ANDROID__ // Layoutlib does not support parcel
\ No newline at end of file
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 7ef0f77..9a6d5d7 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -30,7 +30,6 @@
#include <camera/Camera.h>
#include <media/mediarecorder.h>
#include <media/MediaMetricsItem.h>
-#include <media/MicrophoneInfo.h>
#include <media/stagefright/PersistentSurface.h>
#include <utils/threads.h>
@@ -774,7 +773,7 @@
}
jint jStatus = AUDIO_JAVA_SUCCESS;
- std::vector<media::MicrophoneInfo> activeMicrophones;
+ std::vector<media::MicrophoneInfoFw> activeMicrophones;
status_t status = mr->getActiveMicrophones(&activeMicrophones);
if (status != NO_ERROR) {
ALOGE_IF(status != NO_ERROR, "MediaRecorder::getActiveMicrophones error %d", status);
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index dcddde4..210a387 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -131,6 +131,7 @@
Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
+ Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
Settings.Secure.VR_DISPLAY_MODE,
Settings.Secure.NOTIFICATION_BADGING,
Settings.Secure.NOTIFICATION_DISMISS_RTL,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 1c5e6ea..39cd24a 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -191,6 +191,8 @@
ANY_STRING_VALIDATOR);
VALIDATORS.put(Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS,
ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Secure.ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
+ ANY_STRING_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_WAKE_ENABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index ed6e619..ab36d58 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -51,9 +51,12 @@
defaultClockProvider: ClockProvider,
val fallbackClockId: ClockId = DEFAULT_CLOCK_ID,
) {
- // Usually this would be a typealias, but a SAM provides better java interop
- fun interface ClockChangeListener {
- fun onClockChanged()
+ interface ClockChangeListener {
+ // Called when the active clock changes
+ fun onCurrentClockChanged() {}
+
+ // Called when the list of available clocks changes
+ fun onAvailableClocksChanged() {}
}
private val availableClocks = mutableMapOf<ClockId, ClockInfo>()
@@ -92,7 +95,7 @@
protected set(value) {
if (field != value) {
field = value
- scope.launch(mainDispatcher) { onClockChanged() }
+ scope.launch(mainDispatcher) { onClockChanged { it.onCurrentClockChanged() } }
}
}
@@ -164,9 +167,9 @@
Assert.isNotMainThread()
}
- private fun onClockChanged() {
+ private fun onClockChanged(func: (ClockChangeListener) -> Unit) {
assertMainThread()
- clockChangeListeners.forEach { it.onClockChanged() }
+ clockChangeListeners.forEach(func)
}
private fun mutateSetting(mutator: (ClockSettings) -> ClockSettings) {
@@ -241,6 +244,7 @@
}
private fun connectClocks(provider: ClockProvider) {
+ var isAvailableChanged = false
val currentId = currentClockId
for (clock in provider.getClocks()) {
val id = clock.clockId
@@ -251,10 +255,11 @@
"Clock Id conflict: $id is registered by both " +
"${provider::class.simpleName} and ${current.provider::class.simpleName}"
)
- return
+ continue
}
availableClocks[id] = ClockInfo(clock, provider)
+ isAvailableChanged = true
if (DEBUG) {
Log.i(TAG, "Added ${clock.clockId}")
}
@@ -263,24 +268,35 @@
if (DEBUG) {
Log.i(TAG, "Current clock ($currentId) was connected")
}
- onClockChanged()
+ onClockChanged { it.onCurrentClockChanged() }
}
}
+
+ if (isAvailableChanged) {
+ onClockChanged { it.onAvailableClocksChanged() }
+ }
}
private fun disconnectClocks(provider: ClockProvider) {
+ var isAvailableChanged = false
val currentId = currentClockId
for (clock in provider.getClocks()) {
availableClocks.remove(clock.clockId)
+ isAvailableChanged = true
+
if (DEBUG) {
Log.i(TAG, "Removed ${clock.clockId}")
}
if (currentId == clock.clockId) {
Log.w(TAG, "Current clock ($currentId) was disconnected")
- onClockChanged()
+ onClockChanged { it.onCurrentClockChanged() }
}
}
+
+ if (isAvailableChanged) {
+ onClockChanged { it.onAvailableClocksChanged() }
+ }
}
fun getClocks(): List<ClockMetadata> {
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 176bb6b..ec860b5 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -451,7 +451,6 @@
-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
-packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt
-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsController.kt
-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt
@@ -736,7 +735,6 @@
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/ShadeExpansionStateManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerOldImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
index 91f3309..26eefa9 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
@@ -252,49 +252,49 @@
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 90.0,
(s) -> highestSurface(s));
- public static final DynamicColor primaryFixedDarker =
+ public static final DynamicColor primaryFixedDim =
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 80.0,
(s) -> highestSurface(s));
public static final DynamicColor onPrimaryFixed =
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 10.0,
- (s) -> primaryFixedDarker);
+ (s) -> primaryFixedDim);
public static final DynamicColor onPrimaryFixedVariant =
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 30.0,
- (s) -> primaryFixedDarker);
+ (s) -> primaryFixedDim);
public static final DynamicColor secondaryFixed =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 90.0,
(s) -> highestSurface(s));
- public static final DynamicColor secondaryFixedDarker =
+ public static final DynamicColor secondaryFixedDim =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 80.0,
(s) -> highestSurface(s));
public static final DynamicColor onSecondaryFixed =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 10.0,
- (s) -> secondaryFixedDarker);
+ (s) -> secondaryFixedDim);
public static final DynamicColor onSecondaryFixedVariant =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 30.0,
- (s) -> secondaryFixedDarker);
+ (s) -> secondaryFixedDim);
public static final DynamicColor tertiaryFixed =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 90.0,
(s) -> highestSurface(s));
- public static final DynamicColor tertiaryFixedDarker =
+ public static final DynamicColor tertiaryFixedDim =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 80.0,
(s) -> highestSurface(s));
public static final DynamicColor onTertiaryFixed =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 10.0,
- (s) -> tertiaryFixedDarker);
+ (s) -> tertiaryFixedDim);
public static final DynamicColor onTertiaryFixedVariant =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 30.0,
- (s) -> tertiaryFixedDarker);
+ (s) -> tertiaryFixedDim);
/**
* These colors were present in Android framework before Android U, and used by MDC controls.
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 12e5f19..558cbd4 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -460,7 +460,7 @@
<integer name="watch_heap_limit">256000</integer>
<!-- SystemUI Plugins that can be loaded on user builds. -->
- <string-array name="config_pluginWhitelist" translatable="false">
+ <string-array name="config_pluginAllowlist" translatable="false">
<item>com.android.systemui</item>
</string-array>
@@ -834,7 +834,7 @@
<string name="config_wallpaperPickerPackage" translatable="false">
com.android.wallpaper
</string>
-
+
<!-- Whether the floating rotation button should be on the left/right in the device's natural
orientation -->
<bool name="floating_rotation_button_position_left">true</bool>
diff --git a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
index ead1a10..c4f1ce8 100644
--- a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
@@ -29,8 +29,9 @@
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
-import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_WAKE
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD
import android.util.Log
import com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser
import com.android.systemui.Dumpable
@@ -60,9 +61,27 @@
* Indicates the origin for an active unlock request.
*/
enum class ActiveUnlockRequestOrigin {
+ /**
+ * Trigger ActiveUnlock on wake ups that'd trigger FaceAuth, see [FaceWakeUpTriggersConfig]
+ */
WAKE,
+
+ /**
+ * Trigger ActiveUnlock on unlock intents. This includes the bouncer showing or tapping on
+ * a notification. May also include wakeups: [wakeupsConsideredUnlockIntents].
+ */
UNLOCK_INTENT,
+
+ /**
+ * Trigger ActiveUnlock on biometric failures. This may include soft errors depending on
+ * the other settings. See: [faceErrorsToTriggerBiometricFailOn],
+ * [faceAcquireInfoToTriggerBiometricFailOn].
+ */
BIOMETRIC_FAIL,
+
+ /**
+ * Trigger ActiveUnlock when the assistant is triggered.
+ */
ASSISTANT,
}
@@ -85,6 +104,7 @@
private var faceAcquireInfoToTriggerBiometricFailOn = mutableSetOf<Int>()
private var onUnlockIntentWhenBiometricEnrolled = mutableSetOf<Int>()
private var wakeupsConsideredUnlockIntents = mutableSetOf<Int>()
+ private var wakeupsToForceDismissKeyguard = mutableSetOf<Int>()
private val settingsObserver = object : ContentObserver(handler) {
private val wakeUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE)
@@ -97,6 +117,8 @@
secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED)
private val wakeupsConsideredUnlockIntentsUri =
secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS)
+ private val wakeupsToForceDismissKeyguardUri =
+ secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD)
fun register() {
registerUri(
@@ -108,6 +130,7 @@
faceAcquireInfoUri,
unlockIntentWhenBiometricEnrolledUri,
wakeupsConsideredUnlockIntentsUri,
+ wakeupsToForceDismissKeyguardUri,
)
)
@@ -182,6 +205,15 @@
wakeupsConsideredUnlockIntents,
setOf(WAKE_REASON_UNFOLD_DEVICE))
}
+
+ if (selfChange || uris.contains(wakeupsToForceDismissKeyguardUri)) {
+ processStringArray(
+ secureSettings.getStringForUser(
+ ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
+ getCurrentUser()),
+ wakeupsToForceDismissKeyguard,
+ setOf(WAKE_REASON_UNFOLD_DEVICE))
+ }
}
/**
@@ -249,6 +281,14 @@
}
/**
+ * Whether the PowerManager wake reason should force dismiss the keyguard if active
+ * unlock is successful.
+ */
+ fun shouldWakeupForceDismissKeyguard(pmWakeReason: Int): Boolean {
+ return wakeupsToForceDismissKeyguard.contains(pmWakeReason)
+ }
+
+ /**
* Whether to trigger active unlock based on where the request is coming from and
* the current settings.
*/
@@ -321,6 +361,9 @@
pw.println(" activeUnlockWakeupsConsideredUnlockIntents=${
wakeupsConsideredUnlockIntents.map { PowerManager.wakeReasonToString(it) }
}")
+ pw.println(" activeUnlockFromWakeupsToAlwaysDismissKeyguard=${
+ wakeupsToForceDismissKeyguard.map { PowerManager.wakeReasonToString(it) }
+ }")
pw.println("Current state:")
keyguardUpdateMonitor?.let {
diff --git a/packages/SystemUI/src/com/android/keyguard/FaceWakeUpTriggersConfig.kt b/packages/SystemUI/src/com/android/keyguard/FaceWakeUpTriggersConfig.kt
index a0c43fb..788a66d 100644
--- a/packages/SystemUI/src/com/android/keyguard/FaceWakeUpTriggersConfig.kt
+++ b/packages/SystemUI/src/com/android/keyguard/FaceWakeUpTriggersConfig.kt
@@ -29,7 +29,7 @@
import java.util.stream.Collectors
import javax.inject.Inject
-/** Determines which device wake-ups should trigger face authentication. */
+/** Determines which device wake-ups should trigger passive authentication. */
@SysUISingleton
class FaceWakeUpTriggersConfig
@Inject
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index f1b90e3..5ec59ab 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -151,8 +151,13 @@
mLogBuffer = logBuffer;
mView.setLogBuffer(mLogBuffer);
- mClockChangedListener = () -> {
- setClock(mClockRegistry.createCurrentClock());
+ mClockChangedListener = new ClockRegistry.ClockChangeListener() {
+ @Override
+ public void onCurrentClockChanged() {
+ setClock(mClockRegistry.createCurrentClock());
+ }
+ @Override
+ public void onAvailableClocksChanged() { }
};
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt
index 998dc09..57130ed 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt
@@ -27,6 +27,7 @@
override var userId: Int = 0,
override var listening: Boolean = false,
// keepSorted
+ var alternateBouncerShowing: Boolean = false,
var biometricEnabledForUser: Boolean = false,
var bouncerIsOrWillShow: Boolean = false,
var canSkipBouncer: Boolean = false,
@@ -57,6 +58,7 @@
userId.toString(),
listening.toString(),
// keep sorted
+ alternateBouncerShowing.toString(),
biometricEnabledForUser.toString(),
bouncerIsOrWillShow.toString(),
canSkipBouncer.toString(),
@@ -96,6 +98,7 @@
userId = model.userId
listening = model.listening
// keep sorted
+ alternateBouncerShowing = model.alternateBouncerShowing
biometricEnabledForUser = model.biometricEnabledForUser
bouncerIsOrWillShow = model.bouncerIsOrWillShow
canSkipBouncer = model.canSkipBouncer
@@ -141,6 +144,7 @@
"userId",
"listening",
// keep sorted
+ "alternateBouncerShowing",
"biometricAllowedForUser",
"bouncerIsOrWillShow",
"canSkipBouncer",
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 5b628f8..438c4d2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1942,11 +1942,23 @@
FACE_AUTH_UPDATED_STARTED_WAKING_UP.setExtraInfo(pmWakeReason);
updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
FACE_AUTH_UPDATED_STARTED_WAKING_UP);
- requestActiveUnlock(
+
+ final ActiveUnlockConfig.ActiveUnlockRequestOrigin requestOrigin =
mActiveUnlockConfig.isWakeupConsideredUnlockIntent(pmWakeReason)
? ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT
- : ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE,
- "wakingUp - " + PowerManager.wakeReasonToString(pmWakeReason));
+ : ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE;
+ final String reason = "wakingUp - " + PowerManager.wakeReasonToString(pmWakeReason);
+ if (mActiveUnlockConfig.shouldWakeupForceDismissKeyguard(pmWakeReason)) {
+ requestActiveUnlockDismissKeyguard(
+ requestOrigin,
+ reason
+ );
+ } else {
+ requestActiveUnlock(
+ requestOrigin,
+ reason
+ );
+ }
} else {
mLogger.logSkipUpdateFaceListeningOnWakeup(pmWakeReason);
}
@@ -2606,6 +2618,7 @@
}
}
+
/**
* Attempts to trigger active unlock from trust agent.
* Only dismisses the keyguard under certain conditions.
@@ -2648,6 +2661,7 @@
ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT,
"alternateBouncer");
}
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
private boolean shouldTriggerActiveUnlock() {
@@ -2732,7 +2746,7 @@
|| shouldListenForFingerprintAssistant
|| (mKeyguardOccluded && mIsDreaming)
|| (mKeyguardOccluded && userDoesNotHaveTrust
- && (mOccludingAppRequestingFp || isUdfps));
+ && (mOccludingAppRequestingFp || isUdfps || mAlternateBouncerShowing));
// Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
// instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
@@ -2773,6 +2787,7 @@
System.currentTimeMillis(),
user,
shouldListen,
+ mAlternateBouncerShowing,
biometricEnabledForUser,
mPrimaryBouncerIsOrWillBeShowing,
userCanSkipBouncer,
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 413a3ca..bfd99d3 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -468,6 +468,17 @@
}
}
+ /**
+ * @return whether the userUnlockedWithBiometric state changed
+ */
+ private boolean updateUserUnlockedWithBiometric() {
+ final boolean wasUserUnlockedWithBiometric = mUserUnlockedWithBiometric;
+ mUserUnlockedWithBiometric =
+ mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
+ KeyguardUpdateMonitor.getCurrentUser());
+ return wasUserUnlockedWithBiometric != mUserUnlockedWithBiometric;
+ }
+
private StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@Override
@@ -505,11 +516,7 @@
@Override
public void onBiometricsCleared() {
- final boolean wasUserUnlockedWithBiometric = mUserUnlockedWithBiometric;
- mUserUnlockedWithBiometric =
- mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
- KeyguardUpdateMonitor.getCurrentUser());
- if (wasUserUnlockedWithBiometric != mUserUnlockedWithBiometric) {
+ if (updateUserUnlockedWithBiometric()) {
updateVisibility();
}
}
@@ -518,10 +525,8 @@
public void onBiometricRunningStateChanged(boolean running,
BiometricSourceType biometricSourceType) {
final boolean wasRunningFps = mRunningFPS;
- final boolean wasUserUnlockedWithBiometric = mUserUnlockedWithBiometric;
- mUserUnlockedWithBiometric =
- mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
- KeyguardUpdateMonitor.getCurrentUser());
+ final boolean userUnlockedWithBiometricChanged =
+ updateUserUnlockedWithBiometric();
if (biometricSourceType == FINGERPRINT) {
mRunningFPS = running;
@@ -539,8 +544,7 @@
}
}
- if (wasUserUnlockedWithBiometric != mUserUnlockedWithBiometric
- || wasRunningFps != mRunningFPS) {
+ if (userUnlockedWithBiometricChanged || wasRunningFps != mRunningFPS) {
updateVisibility();
}
}
@@ -551,6 +555,7 @@
@Override
public void onUnlockedChanged() {
mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen();
+ updateUserUnlockedWithBiometric();
updateKeyguardShowing();
updateVisibility();
}
@@ -568,9 +573,7 @@
updateKeyguardShowing();
if (mIsKeyguardShowing) {
- mUserUnlockedWithBiometric =
- mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
- KeyguardUpdateMonitor.getCurrentUser());
+ updateUserUnlockedWithBiometric();
}
updateVisibility();
}
diff --git a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
index 621b99d..6721c5d 100644
--- a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
@@ -31,6 +31,7 @@
import com.android.systemui.controls.controller.ControlsFavoritePersistenceWrapper
import com.android.systemui.keyguard.domain.backup.KeyguardQuickAffordanceBackupHelper
import com.android.systemui.people.widget.PeopleBackupHelper
+import com.android.systemui.settings.UserFileManagerImpl
/**
* Helper for backing up elements in SystemUI
@@ -58,17 +59,8 @@
override fun onCreate(userHandle: UserHandle, operationType: Int) {
super.onCreate()
- // The map in mapOf is guaranteed to be order preserving
- val controlsMap = mapOf(CONTROLS to getPPControlsFile(this))
- NoOverwriteFileBackupHelper(controlsDataLock, this, controlsMap).also {
- addHelper(NO_OVERWRITE_FILES_BACKUP_KEY, it)
- }
- // Conversations widgets backup only works for system user, because widgets' information is
- // stored in system user's SharedPreferences files and we can't open those from other users.
- if (!userHandle.isSystem) {
- return
- }
+ addControlsHelper(userHandle.identifier)
val keys = PeopleBackupHelper.getFilesToBackup()
addHelper(
@@ -95,6 +87,18 @@
sendBroadcastAsUser(intent, UserHandle.SYSTEM, PERMISSION_SELF)
}
+ private fun addControlsHelper(userId: Int) {
+ val file = UserFileManagerImpl.createFile(
+ userId = userId,
+ fileName = CONTROLS,
+ )
+ // The map in mapOf is guaranteed to be order preserving
+ val controlsMap = mapOf(file.getPath() to getPPControlsFile(this, userId))
+ NoOverwriteFileBackupHelper(controlsDataLock, this, controlsMap).also {
+ addHelper(NO_OVERWRITE_FILES_BACKUP_KEY, it)
+ }
+ }
+
/**
* Helper class for restoring files ONLY if they are not present.
*
@@ -136,17 +140,21 @@
}
}
-private fun getPPControlsFile(context: Context): () -> Unit {
+private fun getPPControlsFile(context: Context, userId: Int): () -> Unit {
return {
- val filesDir = context.filesDir
- val file = Environment.buildPath(filesDir, BackupHelper.CONTROLS)
+ val file = UserFileManagerImpl.createFile(
+ userId = userId,
+ fileName = BackupHelper.CONTROLS,
+ )
if (file.exists()) {
- val dest =
- Environment.buildPath(filesDir, AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME)
+ val dest = UserFileManagerImpl.createFile(
+ userId = userId,
+ fileName = AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME,
+ )
file.copyTo(dest)
val jobScheduler = context.getSystemService(JobScheduler::class.java)
jobScheduler?.schedule(
- AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context)
+ AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context, userId)
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt
index 0a6335e..b3c18fb 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt
@@ -21,8 +21,10 @@
import android.app.job.JobService
import android.content.ComponentName
import android.content.Context
+import android.os.PersistableBundle
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.backup.BackupHelper
+import com.android.systemui.settings.UserFileManagerImpl
import java.io.File
import java.util.concurrent.Executor
import java.util.concurrent.TimeUnit
@@ -33,14 +35,14 @@
* This file is a copy of the `controls_favorites.xml` file restored from a back up. It is used to
* keep track of controls that were restored but its corresponding app has not been installed yet.
*/
-class AuxiliaryPersistenceWrapper @VisibleForTesting internal constructor(
- wrapper: ControlsFavoritePersistenceWrapper
-) {
+class AuxiliaryPersistenceWrapper
+@VisibleForTesting
+internal constructor(wrapper: ControlsFavoritePersistenceWrapper) {
constructor(
file: File,
executor: Executor
- ): this(ControlsFavoritePersistenceWrapper(file, executor))
+ ) : this(ControlsFavoritePersistenceWrapper(file, executor))
companion object {
const val AUXILIARY_FILE_NAME = "aux_controls_favorites.xml"
@@ -48,9 +50,7 @@
private var persistenceWrapper: ControlsFavoritePersistenceWrapper = wrapper
- /**
- * Access the current list of favorites as tracked by the auxiliary file
- */
+ /** Access the current list of favorites as tracked by the auxiliary file */
var favorites: List<StructureInfo> = emptyList()
private set
@@ -73,18 +73,19 @@
* exist, it will be initialized to an empty list.
*/
fun initialize() {
- favorites = if (persistenceWrapper.fileExists) {
- persistenceWrapper.readFavorites()
- } else {
- emptyList()
- }
+ favorites =
+ if (persistenceWrapper.fileExists) {
+ persistenceWrapper.readFavorites()
+ } else {
+ emptyList()
+ }
}
/**
* Gets the list of favorite controls as persisted in the auxiliary file for a given component.
*
- * When the favorites for that application are returned, they will be removed from the
- * auxiliary file immediately, so they won't be retrieved again.
+ * When the favorites for that application are returned, they will be removed from the auxiliary
+ * file immediately, so they won't be retrieved again.
* @param componentName the name of the service that provided the controls
* @return a list of structures with favorites
*/
@@ -103,20 +104,20 @@
}
}
- /**
- * [JobService] to delete the auxiliary file after a week.
- */
+ /** [JobService] to delete the auxiliary file after a week. */
class DeletionJobService : JobService() {
companion object {
- @VisibleForTesting
- internal val DELETE_FILE_JOB_ID = 1000
+ @VisibleForTesting internal val DELETE_FILE_JOB_ID = 1000
+ @VisibleForTesting internal val USER = "USER"
private val WEEK_IN_MILLIS = TimeUnit.DAYS.toMillis(7)
- fun getJobForContext(context: Context): JobInfo {
+ fun getJobForContext(context: Context, targetUserId: Int): JobInfo {
val jobId = DELETE_FILE_JOB_ID + context.userId
val componentName = ComponentName(context, DeletionJobService::class.java)
+ val bundle = PersistableBundle().also { it.putInt(USER, targetUserId) }
return JobInfo.Builder(jobId, componentName)
.setMinimumLatency(WEEK_IN_MILLIS)
.setPersisted(true)
+ .setExtras(bundle)
.build()
}
}
@@ -127,8 +128,14 @@
}
override fun onStartJob(params: JobParameters): Boolean {
+ val userId = params.getExtras()?.getInt(USER, 0) ?: 0
synchronized(BackupHelper.controlsDataLock) {
- baseContext.deleteFile(AUXILIARY_FILE_NAME)
+ val file =
+ UserFileManagerImpl.createFile(
+ userId = userId,
+ fileName = AUXILIARY_FILE_NAME,
+ )
+ baseContext.deleteFile(file.getPath())
}
return false
}
@@ -137,4 +144,4 @@
return true // reschedule and try again if the job was stopped without completing
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index ad5ad13..9921b1f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -32,6 +32,7 @@
import com.android.systemui.dreams.AssistantAttentionMonitor
import com.android.systemui.dreams.DreamMonitor
import com.android.systemui.globalactions.GlobalActionsComponent
+import com.android.systemui.keyboard.PhysicalKeyboardCoreStartable
import com.android.systemui.keyboard.KeyboardUI
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.data.quickaffordance.MuteQuickAffordanceCoreStartable
@@ -294,6 +295,11 @@
@ClassKey(StylusUsiPowerStartable::class)
abstract fun bindStylusUsiPowerStartable(sysui: StylusUsiPowerStartable): CoreStartable
+ @Binds
+ @IntoMap
+ @ClassKey(PhysicalKeyboardCoreStartable::class)
+ abstract fun bindKeyboardCoreStartable(listener: PhysicalKeyboardCoreStartable): CoreStartable
+
/** Inject into MuteQuickAffordanceCoreStartable*/
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index a1050ec..f6bb85f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -48,6 +48,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.FlagsModule;
import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.keyboard.KeyboardModule;
import com.android.systemui.keyguard.data.BouncerViewModule;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.mediaprojection.appselector.MediaProjectionModule;
@@ -151,6 +152,7 @@
SystemPropertiesFlagsModule.class,
FooterActionsModule.class,
GarbageMonitorModule.class,
+ KeyboardModule.class,
LogModule.class,
MediaProjectionModule.class,
MotionToolModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt
new file mode 100644
index 0000000..e9b8908
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardModule.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard
+
+import dagger.Module
+
+@Module abstract class KeyboardModule
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
new file mode 100644
index 0000000..b0f9c4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyboard
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import javax.inject.Inject
+
+/** A [CoreStartable] that launches components interested in physical keyboard interaction. */
+@SysUISingleton
+class PhysicalKeyboardCoreStartable
+@Inject
+constructor(
+ private val featureFlags: FeatureFlags,
+) : CoreStartable {
+ override fun start() {
+ if (featureFlags.isEnabled(Flags.KEYBOARD_BACKLIGHT_INDICATOR)) {
+ // TODO(b/268645743) start listening for keyboard backlight brightness
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 2fb53f1..0ca9115 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -928,7 +928,7 @@
}
// The smartspace is not visible if the bouncer is showing, so don't shared element it.
- if (keyguardStateController.isBouncerShowing) {
+ if (keyguardStateController.isPrimaryBouncerShowing) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c5ea241..54fc5b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1150,12 +1150,12 @@
private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
new KeyguardStateController.Callback() {
@Override
- public void onBouncerShowingChanged() {
+ public void onPrimaryBouncerShowingChanged() {
synchronized (KeyguardViewMediator.this) {
- if (mKeyguardStateController.isBouncerShowing()) {
+ if (mKeyguardStateController.isPrimaryBouncerShowing()) {
mPendingPinLock = false;
}
- adjustStatusBarLocked(mKeyguardStateController.isBouncerShowing(), false);
+ adjustStatusBarLocked(mKeyguardStateController.isPrimaryBouncerShowing(), false);
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
index 091acad..4331fe6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
@@ -68,8 +68,8 @@
val resourceUpdateRequests: StateFlow<Boolean>
val bouncerPromptReason: Int
val bouncerErrorMessage: CharSequence?
- val isAlternateBouncerVisible: StateFlow<Boolean>
- val isAlternateBouncerUIAvailable: StateFlow<Boolean>
+ val alternateBouncerVisible: StateFlow<Boolean>
+ val alternateBouncerUIAvailable: StateFlow<Boolean>
var lastAlternateBouncerVisibleTime: Long
fun setPrimaryScrimmed(isScrimmed: Boolean)
@@ -159,12 +159,12 @@
get() = viewMediatorCallback.consumeCustomMessage()
/** Values associated with the AlternateBouncer */
- private val _isAlternateBouncerVisible = MutableStateFlow(false)
- override val isAlternateBouncerVisible = _isAlternateBouncerVisible.asStateFlow()
+ private val _alternateBouncerVisible = MutableStateFlow(false)
+ override val alternateBouncerVisible = _alternateBouncerVisible.asStateFlow()
override var lastAlternateBouncerVisibleTime: Long = NOT_VISIBLE
- private val _isAlternateBouncerUIAvailable = MutableStateFlow(false)
- override val isAlternateBouncerUIAvailable: StateFlow<Boolean> =
- _isAlternateBouncerUIAvailable.asStateFlow()
+ private val _alternateBouncerUIAvailable = MutableStateFlow(false)
+ override val alternateBouncerUIAvailable: StateFlow<Boolean> =
+ _alternateBouncerUIAvailable.asStateFlow()
init {
setUpLogging()
@@ -179,16 +179,16 @@
}
override fun setAlternateVisible(isVisible: Boolean) {
- if (isVisible && !_isAlternateBouncerVisible.value) {
+ if (isVisible && !_alternateBouncerVisible.value) {
lastAlternateBouncerVisibleTime = clock.uptimeMillis()
} else if (!isVisible) {
lastAlternateBouncerVisibleTime = NOT_VISIBLE
}
- _isAlternateBouncerVisible.value = isVisible
+ _alternateBouncerVisible.value = isVisible
}
override fun setAlternateBouncerUIAvailable(isAvailable: Boolean) {
- _isAlternateBouncerUIAvailable.value = isAvailable
+ _alternateBouncerUIAvailable.value = isAvailable
}
override fun setPrimaryShow(keyguardBouncerModel: KeyguardBouncerModel?) {
@@ -290,7 +290,7 @@
resourceUpdateRequests
.logDiffsForTable(buffer, "", "ResourceUpdateRequests", false)
.launchIn(applicationScope)
- isAlternateBouncerUIAvailable
+ alternateBouncerUIAvailable
.logDiffsForTable(buffer, "", "IsAlternateBouncerUIAvailable", false)
.launchIn(applicationScope)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index db95562..a3b3d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -86,9 +86,6 @@
/** Observable for the signal that keyguard is about to go away. */
val isKeyguardGoingAway: Flow<Boolean>
- /** Observable for whether the bouncer is showing. */
- val isBouncerShowing: Flow<Boolean>
-
/** Is the always-on display available to be used? */
val isAodAvailable: Flow<Boolean>
@@ -304,29 +301,6 @@
awaitClose { keyguardStateController.removeCallback(callback) }
}
- override val isBouncerShowing: Flow<Boolean> = conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onBouncerShowingChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isBouncerShowing,
- TAG,
- "updated isBouncerShowing"
- )
- }
- }
-
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isBouncerShowing,
- TAG,
- "initial isBouncerShowing"
- )
-
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
-
override val isDozing: Flow<Boolean> =
conflatedCallbackFlow {
val callback =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
index 0e865ce..fa6efa5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
@@ -29,16 +29,9 @@
) :
SharedPreferencesBackupHelper(
context,
- if (UserFileManagerImpl.isPrimaryUser(userId)) {
- KeyguardQuickAffordanceSelectionManager.FILE_NAME
- } else {
- UserFileManagerImpl.secondaryUserFile(
- context = context,
- fileName = KeyguardQuickAffordanceSelectionManager.FILE_NAME,
- directoryName = UserFileManagerImpl.SHARED_PREFS,
- userId = userId,
- )
- .also { UserFileManagerImpl.ensureParentDirExists(it) }
- .toString()
- }
+ UserFileManagerImpl.createFile(
+ userId = userId,
+ fileName = KeyguardQuickAffordanceSelectionManager.FILE_NAME,
+ )
+ .getPath()
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
index 6452e0e..dfe1038 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
@@ -44,7 +44,7 @@
var legacyAlternateBouncer: LegacyAlternateBouncer? = null
var legacyAlternateBouncerVisibleTime: Long = NOT_VISIBLE
- val isVisible: Flow<Boolean> = bouncerRepository.isAlternateBouncerVisible
+ val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
/**
* Sets the correct bouncer states to show the alternate bouncer if it can show.
@@ -86,7 +86,7 @@
fun isVisibleState(): Boolean {
return if (isModernAlternateBouncerEnabled) {
- bouncerRepository.isAlternateBouncerVisible.value
+ bouncerRepository.alternateBouncerVisible.value
} else {
legacyAlternateBouncer?.isShowingAlternateBouncer ?: false
}
@@ -98,7 +98,7 @@
fun canShowAlternateBouncerForFingerprint(): Boolean {
return if (isModernAlternateBouncerEnabled) {
- bouncerRepository.isAlternateBouncerUIAvailable.value &&
+ bouncerRepository.alternateBouncerUIAvailable.value &&
biometricSettingsRepository.isFingerprintEnrolled.value &&
biometricSettingsRepository.isStrongBiometricAllowed.value &&
biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value &&
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
new file mode 100644
index 0000000..310f44d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.animation.ValueAnimator
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionInfo
+import com.android.systemui.keyguard.shared.model.WakefulnessState
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+
+@SysUISingleton
+class FromAlternateBouncerTransitionInteractor
+@Inject
+constructor(
+ @Application private val scope: CoroutineScope,
+ private val keyguardInteractor: KeyguardInteractor,
+ private val keyguardTransitionRepository: KeyguardTransitionRepository,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+) : TransitionInteractor(FromAlternateBouncerTransitionInteractor::class.simpleName!!) {
+
+ override fun start() {
+ listenForAlternateBouncerToGone()
+ listenForAlternateBouncerToLockscreenAodOrDozing()
+ listenForAlternateBouncerToPrimaryBouncer()
+ }
+
+ private fun listenForAlternateBouncerToLockscreenAodOrDozing() {
+ scope.launch {
+ keyguardInteractor.alternateBouncerShowing
+ // Add a slight delay, as alternateBouncer and primaryBouncer showing event changes
+ // will arrive with a small gap in time. This prevents a transition to LOCKSCREEN
+ // happening prematurely.
+ .onEach { delay(50) }
+ .sample(
+ combine(
+ keyguardInteractor.primaryBouncerShowing,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ keyguardInteractor.wakefulnessModel,
+ keyguardInteractor.isAodAvailable,
+ ::toQuad
+ ),
+ ::toQuint
+ )
+ .collect {
+ (
+ isAlternateBouncerShowing,
+ isPrimaryBouncerShowing,
+ lastStartedTransitionStep,
+ wakefulnessState,
+ isAodAvailable
+ ) ->
+ if (
+ !isAlternateBouncerShowing &&
+ !isPrimaryBouncerShowing &&
+ lastStartedTransitionStep.to == KeyguardState.ALTERNATE_BOUNCER
+ ) {
+ val to =
+ if (
+ wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP ||
+ wakefulnessState.state == WakefulnessState.ASLEEP
+ ) {
+ if (isAodAvailable) {
+ KeyguardState.AOD
+ } else {
+ KeyguardState.DOZING
+ }
+ } else {
+ KeyguardState.LOCKSCREEN
+ }
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = to,
+ animator = getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun listenForAlternateBouncerToGone() {
+ scope.launch {
+ keyguardInteractor.isKeyguardGoingAway
+ .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
+ .collect { (isKeyguardGoingAway, keyguardState) ->
+ if (isKeyguardGoingAway && keyguardState == KeyguardState.ALTERNATE_BOUNCER) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = KeyguardState.GONE,
+ animator = getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun listenForAlternateBouncerToPrimaryBouncer() {
+ scope.launch {
+ keyguardInteractor.primaryBouncerShowing
+ .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { (isPrimaryBouncerShowing, startedKeyguardState) ->
+ if (
+ isPrimaryBouncerShowing &&
+ startedKeyguardState.to == KeyguardState.ALTERNATE_BOUNCER
+ ) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animator = getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun getAnimator(): ValueAnimator {
+ return ValueAnimator().apply {
+ interpolator = Interpolators.LINEAR
+ duration = TRANSITION_DURATION_MS
+ }
+ }
+
+ companion object {
+ private const val TRANSITION_DURATION_MS = 300L
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 5674e2a..d01f489 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -33,7 +33,6 @@
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -53,9 +52,10 @@
listenForLockscreenToOccluded()
listenForLockscreenToCamera()
listenForLockscreenToAodOrDozing()
- listenForLockscreenToBouncer()
+ listenForLockscreenToPrimaryBouncer()
listenForLockscreenToDreaming()
- listenForLockscreenToBouncerDragging()
+ listenForLockscreenToPrimaryBouncerDragging()
+ listenForLockscreenToAlternateBouncer()
}
private fun listenForLockscreenToDreaming() {
@@ -78,9 +78,9 @@
}
}
- private fun listenForLockscreenToBouncer() {
+ private fun listenForLockscreenToPrimaryBouncer() {
scope.launch {
- keyguardInteractor.isBouncerShowing
+ keyguardInteractor.primaryBouncerShowing
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isBouncerShowing, lastStartedTransitionStep) = pair
@@ -91,7 +91,30 @@
TransitionInfo(
ownerName = name,
from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.BOUNCER,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animator = getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun listenForLockscreenToAlternateBouncer() {
+ scope.launch {
+ keyguardInteractor.alternateBouncerShowing
+ .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { pair ->
+ val (isAlternateBouncerShowing, lastStartedTransitionStep) = pair
+ if (
+ isAlternateBouncerShowing &&
+ lastStartedTransitionStep.to == KeyguardState.LOCKSCREEN
+ ) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
animator = getAnimator(),
)
)
@@ -101,7 +124,7 @@
}
/* Starts transitions when manually dragging up the bouncer from the lockscreen. */
- private fun listenForLockscreenToBouncerDragging() {
+ private fun listenForLockscreenToPrimaryBouncerDragging() {
var transitionId: UUID? = null
scope.launch {
shadeRepository.shadeModel
@@ -144,7 +167,7 @@
keyguardTransitionRepository.startTransition(
TransitionInfo(
ownerName = name,
- from = KeyguardState.BOUNCER,
+ from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.LOCKSCREEN,
animator = getAnimator(0.milliseconds)
)
@@ -163,7 +186,7 @@
TransitionInfo(
ownerName = name,
from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.BOUNCER,
+ to = KeyguardState.PRIMARY_BOUNCER,
animator = null,
)
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
similarity index 75%
rename from packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromBouncerTransitionInteractor.kt
rename to packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 0e9c447..b59b413 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -24,62 +24,63 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessState
-import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.sample
-import java.util.UUID
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@SysUISingleton
-class FromBouncerTransitionInteractor
+class FromPrimaryBouncerTransitionInteractor
@Inject
constructor(
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val shadeRepository: ShadeRepository,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor
-) : TransitionInteractor(FromBouncerTransitionInteractor::class.simpleName!!) {
-
- private var transitionId: UUID? = null
+) : TransitionInteractor(FromPrimaryBouncerTransitionInteractor::class.simpleName!!) {
override fun start() {
- listenForBouncerToGone()
- listenForBouncerToLockscreenOrAod()
+ listenForPrimaryBouncerToGone()
+ listenForPrimaryBouncerToLockscreenAodOrDozing()
}
- private fun listenForBouncerToLockscreenOrAod() {
+ private fun listenForPrimaryBouncerToLockscreenAodOrDozing() {
scope.launch {
- keyguardInteractor.isBouncerShowing
+ keyguardInteractor.primaryBouncerShowing
.sample(
combine(
keyguardInteractor.wakefulnessModel,
keyguardTransitionInteractor.startedKeyguardTransitionStep,
- ::Pair
+ keyguardInteractor.isAodAvailable,
+ ::toTriple
),
- ::toTriple
+ ::toQuad
)
- .collect { triple ->
- val (isBouncerShowing, wakefulnessState, lastStartedTransitionStep) = triple
+ .collect {
+ (isBouncerShowing, wakefulnessState, lastStartedTransitionStep, isAodAvailable)
+ ->
if (
- !isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.BOUNCER
+ !isBouncerShowing &&
+ lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER
) {
val to =
if (
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP ||
wakefulnessState.state == WakefulnessState.ASLEEP
) {
- KeyguardState.AOD
+ if (isAodAvailable) {
+ KeyguardState.AOD
+ } else {
+ KeyguardState.DOZING
+ }
} else {
KeyguardState.LOCKSCREEN
}
keyguardTransitionRepository.startTransition(
TransitionInfo(
ownerName = name,
- from = KeyguardState.BOUNCER,
+ from = KeyguardState.PRIMARY_BOUNCER,
to = to,
animator = getAnimator(),
)
@@ -89,17 +90,17 @@
}
}
- private fun listenForBouncerToGone() {
+ private fun listenForPrimaryBouncerToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
+ .sample(keyguardTransitionInteractor.finishedKeyguardState) { a, b -> Pair(a, b) }
.collect { pair ->
val (isKeyguardGoingAway, keyguardState) = pair
- if (isKeyguardGoingAway && keyguardState == KeyguardState.BOUNCER) {
+ if (isKeyguardGoingAway && keyguardState == KeyguardState.PRIMARY_BOUNCER) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
ownerName = name,
- from = KeyguardState.BOUNCER,
+ from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.GONE,
animator = getAnimator(),
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 7e86a5d..d25aff0a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -24,6 +24,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
@@ -56,6 +57,7 @@
private val repository: KeyguardRepository,
private val commandQueue: CommandQueue,
featureFlags: FeatureFlags,
+ bouncerRepository: KeyguardBouncerRepository,
) {
/**
* The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
@@ -121,8 +123,10 @@
val isKeyguardOccluded: Flow<Boolean> = repository.isKeyguardOccluded
/** Whether the keyguard is going away. */
val isKeyguardGoingAway: Flow<Boolean> = repository.isKeyguardGoingAway
- /** Whether the bouncer is showing or not. */
- val isBouncerShowing: Flow<Boolean> = repository.isBouncerShowing
+ /** Whether the primary bouncer is showing or not. */
+ val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerVisible
+ /** Whether the alternate bouncer is showing or not. */
+ val alternateBouncerShowing: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
/** The device wake/sleep state */
val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
/** Observable for the [StatusBarState] */
@@ -142,12 +146,12 @@
if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
combine(
isKeyguardVisible,
- repository.isBouncerShowing,
+ bouncerRepository.primaryBouncerVisible,
onCameraLaunchDetected,
- ) { isKeyguardVisible, isBouncerShowing, cameraLaunchEvent ->
+ ) { isKeyguardVisible, isPrimaryBouncerShowing, cameraLaunchEvent ->
when {
isKeyguardVisible -> false
- isBouncerShowing -> false
+ isPrimaryBouncerShowing -> false
else -> cameraLaunchEvent == CameraLaunchSourceModel.POWER_DOUBLE_TAP
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index d4e23499..51b0277 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -22,7 +22,6 @@
import com.android.systemui.plugins.log.LogLevel.VERBOSE
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
private val TAG = KeyguardTransitionAuditLogger::class.simpleName!!
@@ -46,8 +45,14 @@
}
scope.launch {
- keyguardInteractor.isBouncerShowing.collect {
- logger.log(TAG, VERBOSE, "Bouncer showing", it)
+ keyguardInteractor.primaryBouncerShowing.collect {
+ logger.log(TAG, VERBOSE, "Primary bouncer showing", it)
+ }
+ }
+
+ scope.launch {
+ keyguardInteractor.alternateBouncerShowing.collect {
+ logger.log(TAG, VERBOSE, "Alternate bouncer showing", it)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
index fbed446..efc1bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
@@ -37,13 +37,14 @@
// exhaustive
val ret =
when (it) {
- is FromBouncerTransitionInteractor -> Log.d(TAG, "Started $it")
+ is FromPrimaryBouncerTransitionInteractor -> Log.d(TAG, "Started $it")
is FromAodTransitionInteractor -> Log.d(TAG, "Started $it")
is FromGoneTransitionInteractor -> Log.d(TAG, "Started $it")
is FromLockscreenTransitionInteractor -> Log.d(TAG, "Started $it")
is FromDreamingTransitionInteractor -> Log.d(TAG, "Started $it")
is FromOccludedTransitionInteractor -> Log.d(TAG, "Started $it")
is FromDozingTransitionInteractor -> Log.d(TAG, "Started $it")
+ is FromAlternateBouncerTransitionInteractor -> Log.d(TAG, "Started $it")
}
it.start()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 84bcdf9..1b7da5b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -21,13 +21,12 @@
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
-import com.android.systemui.keyguard.shared.model.KeyguardState.BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.TransitionState
-import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionStep
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -63,9 +62,9 @@
/** LOCKSCREEN->AOD transition information. */
val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD)
- /** LOCKSCREEN->BOUNCER transition information. */
- val lockscreenToBouncerTransition: Flow<TransitionStep> =
- repository.transition(LOCKSCREEN, BOUNCER)
+ /** LOCKSCREEN->PRIMARY_BOUNCER transition information. */
+ val mLockscreenToPrimaryBouncerTransition: Flow<TransitionStep> =
+ repository.transition(LOCKSCREEN, PRIMARY_BOUNCER)
/** LOCKSCREEN->DREAMING transition information. */
val lockscreenToDreamingTransition: Flow<TransitionStep> =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
index a59c407..833eda7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
@@ -86,7 +86,8 @@
KeyguardState.DOZING -> false
KeyguardState.AOD -> false
KeyguardState.DREAMING -> true
- KeyguardState.BOUNCER -> true
+ KeyguardState.ALTERNATE_BOUNCER -> true
+ KeyguardState.PRIMARY_BOUNCER -> true
KeyguardState.LOCKSCREEN -> true
KeyguardState.GONE -> true
KeyguardState.OCCLUDED -> true
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
index 4579e37..e819da9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
@@ -156,7 +156,7 @@
} else {
DejankUtils.postAfterTraversal(showRunnable)
}
- keyguardStateController.notifyBouncerShowing(true)
+ keyguardStateController.notifyPrimaryBouncerShowing(true)
primaryBouncerCallbackInteractor.dispatchStartingToShow()
Trace.endSection()
}
@@ -173,7 +173,7 @@
}
falsingCollector.onBouncerHidden()
- keyguardStateController.notifyBouncerShowing(false /* showing */)
+ keyguardStateController.notifyPrimaryBouncerShowing(false /* showing */)
cancelShowRunnable()
repository.setPrimaryShowingSoon(false)
repository.setPrimaryVisible(false)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
index 81fa233..d9690b7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
@@ -32,7 +32,9 @@
@Binds
@IntoSet
- abstract fun fromBouncer(impl: FromBouncerTransitionInteractor): TransitionInteractor
+ abstract fun fromPrimaryBouncer(
+ impl: FromPrimaryBouncerTransitionInteractor
+ ): TransitionInteractor
@Binds
@IntoSet
@@ -53,4 +55,10 @@
@Binds
@IntoSet
abstract fun fromDozing(impl: FromDozingTransitionInteractor): TransitionInteractor
+
+ @Binds
+ @IntoSet
+ abstract fun fromAlternateBouncer(
+ impl: FromAlternateBouncerTransitionInteractor
+ ): TransitionInteractor
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
index 4d24c14..e3e3527 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
@@ -30,7 +30,26 @@
abstract fun start()
+ fun <A, B, C> toTriple(a: A, b: B, c: C) = Triple(a, b, c)
+
fun <A, B, C> toTriple(a: A, bc: Pair<B, C>) = Triple(a, bc.first, bc.second)
fun <A, B, C> toTriple(ab: Pair<A, B>, c: C) = Triple(ab.first, ab.second, c)
+
+ fun <A, B, C, D> toQuad(a: A, b: B, c: C, d: D) = Quad(a, b, c, d)
+
+ fun <A, B, C, D> toQuad(a: A, bcd: Triple<B, C, D>) = Quad(a, bcd.first, bcd.second, bcd.third)
+
+ fun <A, B, C, D, E> toQuint(a: A, bcde: Quad<B, C, D, E>) =
+ Quint(a, bcde.first, bcde.second, bcde.third, bcde.fourth)
}
+
+data class Quad<A, B, C, D>(val first: A, val second: B, val third: C, val fourth: D)
+
+data class Quint<A, B, C, D, E>(
+ val first: A,
+ val second: B,
+ val third: C,
+ val fourth: D,
+ val fifth: E
+)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
index c757986..87b4321 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
@@ -42,10 +42,15 @@
*/
AOD,
/*
- * The security screen prompt UI, containing PIN, Password, Pattern, and all FPS
- * (Fingerprint Sensor) variations, for the user to verify their credentials
+ * The security screen prompt containing UI to prompt the user to use a biometric credential
+ * (ie: fingerprint). When supported, this may show before showing the primary bouncer.
*/
- BOUNCER,
+ ALTERNATE_BOUNCER,
+ /*
+ * The security screen prompt UI, containing PIN, Password, Pattern for the user to verify their
+ * credentials.
+ */
+ PRIMARY_BOUNCER,
/*
* Device is actively displaying keyguard UI and is not in low-power mode. Device may be
* unlocked if SWIPE security method is used, or if face lockscreen bypass is false.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index d977f91..9aecb5d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -171,7 +171,12 @@
}
private fun setUpClock(parentView: ViewGroup) {
- val clockChangeListener = ClockRegistry.ClockChangeListener { onClockChanged(parentView) }
+ val clockChangeListener =
+ object : ClockRegistry.ClockChangeListener {
+ override fun onCurrentClockChanged() {
+ onClockChanged(parentView)
+ }
+ }
clockRegistry.registerClockChangeListener(clockChangeListener)
disposables.add(
DisposableHandle { clockRegistry.unregisterClockChangeListener(clockChangeListener) }
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index c02fd9c..bb52659 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -265,16 +265,6 @@
return factory.create("MediaCarouselCtlrLog", 20);
}
- /**
- * Provides a {@link LogBuffer} for use in the status bar connectivity pipeline
- */
- @Provides
- @SysUISingleton
- @StatusBarConnectivityLog
- public static LogBuffer provideStatusBarConnectivityBuffer(LogBufferFactory factory) {
- return factory.create("SbConnectivity", 64);
- }
-
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarConnectivityLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarConnectivityLog.java
deleted file mode 100644
index 67cdb72..0000000
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/StatusBarConnectivityLog.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.log.dagger;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.android.systemui.plugins.log.LogBuffer;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-/**
- * A {@link LogBuffer} for status bar connectivity events.
- */
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface StatusBarConnectivityLog {
-}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
index 146633d..95f1419 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java
@@ -121,6 +121,6 @@
@Provides
@Named(PLUGIN_PRIVILEGED)
static List<String> providesPrivilegedPlugins(Context context) {
- return Arrays.asList(context.getResources().getStringArray(R.array.config_pluginWhitelist));
+ return Arrays.asList(context.getResources().getStringArray(R.array.config_pluginAllowlist));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
index bfba6df..bb637dc 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
@@ -32,74 +32,62 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.util.concurrency.DelayableExecutor
import java.io.File
+import java.io.FilenameFilter
import javax.inject.Inject
/**
- * Implementation for retrieving file paths for file storage of system and secondary users. Files
- * lie in {File Directory}/UserFileManager/{User Id} for secondary user. For system user, we use the
- * conventional {File Directory}
+ * Implementation for retrieving file paths for file storage of system and secondary users. For
+ * non-system users, files will be prepended by a special prefix containing the user id.
*/
@SysUISingleton
class UserFileManagerImpl
@Inject
constructor(
- // Context of system process and system user.
private val context: Context,
val userManager: UserManager,
val broadcastDispatcher: BroadcastDispatcher,
@Background val backgroundExecutor: DelayableExecutor
) : UserFileManager, CoreStartable {
companion object {
- private const val FILES = "files"
+ private const val PREFIX = "__USER_"
+ private const val TAG = "UserFileManagerImpl"
+ const val ROOT_DIR = "UserFileManager"
+ const val FILES = "files"
const val SHARED_PREFS = "shared_prefs"
- @VisibleForTesting internal const val ID = "UserFileManager"
-
- /** Returns `true` if the given user ID is that for the primary/system user. */
- fun isPrimaryUser(userId: Int): Boolean {
- return UserHandle(userId).isSystem
- }
/**
- * Returns a [File] pointing to the correct path for a secondary user ID.
- *
- * Note that there is no check for the type of user. This should only be called for
- * secondary users, never for the system user. For that, make sure to call [isPrimaryUser].
- *
- * Note also that there is no guarantee that the parent directory structure for the file
- * exists on disk. For that, call [ensureParentDirExists].
- *
- * @param context The context
- * @param fileName The name of the file
- * @param directoryName The name of the directory that would contain the file
- * @param userId The ID of the user to build a file path for
+ * Returns a File object with a relative path, built from the userId for non-system users
*/
- fun secondaryUserFile(
- context: Context,
- fileName: String,
- directoryName: String,
- userId: Int,
- ): File {
- return Environment.buildPath(
- context.filesDir,
- ID,
- userId.toString(),
- directoryName,
- fileName,
- )
- }
-
- /**
- * Checks to see if parent dir of the file exists. If it does not, we create the parent dirs
- * recursively.
- */
- fun ensureParentDirExists(file: File) {
- val parent = file.parentFile
- if (!parent.exists()) {
- if (!parent.mkdirs()) {
- Log.e(ID, "Could not create parent directory for file: ${file.absolutePath}")
- }
+ fun createFile(fileName: String, userId: Int): File {
+ return if (isSystemUser(userId)) {
+ File(fileName)
+ } else {
+ File(getFilePrefix(userId) + fileName)
}
}
+
+ fun createLegacyFile(context: Context, dir: String, fileName: String, userId: Int): File? {
+ return if (isSystemUser(userId)) {
+ null
+ } else {
+ return Environment.buildPath(
+ context.filesDir,
+ ROOT_DIR,
+ userId.toString(),
+ dir,
+ fileName
+ )
+ }
+ }
+
+ fun getFilePrefix(userId: Int): String {
+ return PREFIX + userId.toString() + "_"
+ }
+
+ /** Returns `true` if the given user ID is that for the system user. */
+ private fun isSystemUser(userId: Int): Boolean {
+ return UserHandle(userId).isSystem
+ }
}
private val broadcastReceiver =
@@ -119,64 +107,87 @@
broadcastDispatcher.registerReceiver(broadcastReceiver, filter, backgroundExecutor)
}
- /** Return the file based on current user. */
+ /**
+ * Return the file based on current user. Files for all users will exist in [context.filesDir],
+ * but non system user files will be prepended with [getFilePrefix].
+ */
override fun getFile(fileName: String, userId: Int): File {
- return if (isPrimaryUser(userId)) {
- Environment.buildPath(context.filesDir, fileName)
- } else {
- val secondaryFile =
- secondaryUserFile(
- context = context,
- userId = userId,
- directoryName = FILES,
- fileName = fileName,
- )
- ensureParentDirExists(secondaryFile)
- secondaryFile
- }
+ val file = File(context.filesDir, createFile(fileName, userId).path)
+ createLegacyFile(context, FILES, fileName, userId)?.run { migrate(file, this) }
+ return file
}
- /** Get shared preferences from user. */
+ /**
+ * Get shared preferences from user. Files for all users will exist in the shared_prefs dir, but
+ * non system user files will be prepended with [getFilePrefix].
+ */
override fun getSharedPreferences(
fileName: String,
@Context.PreferencesMode mode: Int,
userId: Int
): SharedPreferences {
- if (isPrimaryUser(userId)) {
- return context.getSharedPreferences(fileName, mode)
+ val file = createFile(fileName, userId)
+ createLegacyFile(context, SHARED_PREFS, "$fileName.xml", userId)?.run {
+ val path = Environment.buildPath(context.dataDir, SHARED_PREFS, "${file.path}.xml")
+ migrate(path, this)
}
-
- val secondaryUserDir =
- secondaryUserFile(
- context = context,
- fileName = fileName,
- directoryName = SHARED_PREFS,
- userId = userId,
- )
-
- ensureParentDirExists(secondaryUserDir)
- return context.getSharedPreferences(secondaryUserDir, mode)
+ return context.getSharedPreferences(file.path, mode)
}
- /** Remove dirs for deleted users. */
+ /** Remove files for deleted users. */
@VisibleForTesting
internal fun clearDeletedUserData() {
backgroundExecutor.execute {
- val file = Environment.buildPath(context.filesDir, ID)
- if (!file.exists()) return@execute
- val aliveUsers = userManager.aliveUsers.map { it.id.toString() }
- val dirsToDelete = file.list().filter { !aliveUsers.contains(it) }
+ deleteFiles(context.filesDir)
+ deleteFiles(File(context.dataDir, SHARED_PREFS))
+ }
+ }
- dirsToDelete.forEach { dir ->
+ private fun migrate(dest: File, source: File) {
+ if (source.exists()) {
+ try {
+ val parent = source.getParentFile()
+ source.renameTo(dest)
+
+ deleteParentDirsIfEmpty(parent)
+ } catch (e: Exception) {
+ Log.e(TAG, "Failed to rename and delete ${source.path}", e)
+ }
+ }
+ }
+
+ private fun deleteParentDirsIfEmpty(dir: File?) {
+ if (dir != null && dir.listFiles().size == 0) {
+ val priorParent = dir.parentFile
+ val isRoot = dir.name == ROOT_DIR
+ dir.delete()
+
+ if (!isRoot) {
+ deleteParentDirsIfEmpty(priorParent)
+ }
+ }
+ }
+
+ private fun deleteFiles(parent: File) {
+ val aliveUserFilePrefix = userManager.aliveUsers.map { getFilePrefix(it.id) }
+ val filesToDelete =
+ parent.listFiles(
+ FilenameFilter { _, name ->
+ name.startsWith(PREFIX) &&
+ aliveUserFilePrefix.filter { name.startsWith(it) }.isEmpty()
+ }
+ )
+
+ // This can happen in test environments
+ if (filesToDelete == null) {
+ Log.i(TAG, "Empty directory: ${parent.path}")
+ } else {
+ filesToDelete.forEach { file ->
+ Log.i(TAG, "Deleting file: ${file.path}")
try {
- val dirToDelete =
- Environment.buildPath(
- file,
- dir,
- )
- dirToDelete.deleteRecursively()
+ file.delete()
} catch (e: Exception) {
- Log.e(ID, "Deletion failed.", e)
+ Log.e(TAG, "Deletion failed.", e)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 51125b1..46bc887 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -870,7 +870,8 @@
}
for (int i = childCount - 1; i >= 0; i--) {
- updateChildZValue(i, algorithmState, ambientState, i == topHunIndex);
+ childrenOnTop = updateChildZValue(i, childrenOnTop,
+ algorithmState, ambientState, i == topHunIndex);
}
}
@@ -880,11 +881,15 @@
*
* @param isTopHun Whether the child is a top HUN. A top HUN means a HUN that shows on the
* vertically top of screen. Top HUNs should have drop shadows
+ * @param childrenOnTop It is greater than 0 when there's an existing HUN that is elevated
+ * @return childrenOnTop The decimal part represents the fraction of the elevated HUN's height
+ * that overlaps with QQS Panel. The integer part represents the count of
+ * previous HUNs whose Z positions are greater than 0.
*/
- protected void updateChildZValue(int i,
- StackScrollAlgorithmState algorithmState,
- AmbientState ambientState,
- boolean isTopHun) {
+ protected float updateChildZValue(int i, float childrenOnTop,
+ StackScrollAlgorithmState algorithmState,
+ AmbientState ambientState,
+ boolean isTopHun) {
ExpandableView child = algorithmState.visibleChildren.get(i);
ExpandableViewState childViewState = child.getViewState();
float baseZ = ambientState.getBaseZHeight();
@@ -898,16 +903,22 @@
// Handles HUN shadow when Shade is opened, and AmbientState.mScrollY > 0
// Calculate the HUN's z-value based on its overlapping fraction with QQS Panel.
// When scrolling down shade to make HUN back to in-position in Notification Panel,
- // the overlapFraction goes to 0, and the pinned HUN's shadows hides gradually.
- float overlap = ambientState.getTopPadding()
- + ambientState.getStackTranslation() - childViewState.getYTranslation();
-
- if (childViewState.height > 0) { // To avoid 0/0 problems
- // To prevent over-shadow
- float overlapFraction = MathUtils.saturate(overlap / childViewState.height);
- childViewState.setZTranslation(baseZ
- + overlapFraction * mPinnedZTranslationExtra);
+ // The over-lapping fraction goes to 0, and shadows hides gradually.
+ if (childrenOnTop != 0.0f) {
+ // To elevate the later HUN over previous HUN
+ childrenOnTop++;
+ } else {
+ float overlap = ambientState.getTopPadding()
+ + ambientState.getStackTranslation() - childViewState.getYTranslation();
+ // To prevent over-shadow during HUN entry
+ childrenOnTop += Math.min(
+ 1.0f,
+ overlap / childViewState.height
+ );
+ MathUtils.saturate(childrenOnTop);
}
+ childViewState.setZTranslation(baseZ
+ + childrenOnTop * mPinnedZTranslationExtra);
} else if (isTopHun) {
// In case this is a new view that has never been measured before, we don't want to
// elevate if we are currently expanded more than the notification
@@ -935,14 +946,15 @@
}
// Handles HUN shadow when shade is closed.
- // While shade is closed, and during HUN's entry: headerVisibleAmount stays 0, shadow stays.
- // While shade is closed, and HUN is showing: headerVisibleAmount stays 0, shadow stays.
+ // While HUN is showing and Shade is closed: headerVisibleAmount stays 0, shadow stays.
// During HUN-to-Shade (eg. dragging down HUN to open Shade): headerVisibleAmount goes
// gradually from 0 to 1, shadow hides gradually.
// Header visibility is a deprecated concept, we are using headerVisibleAmount only because
// this value nicely goes from 0 to 1 during the HUN-to-Shade process.
+
childViewState.setZTranslation(childViewState.getZTranslation()
+ (1.0f - child.getHeaderVisibleAmount()) * mPinnedZTranslationExtra);
+ return childrenOnTop;
}
public void setIsExpanded(boolean isExpanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
index 4a5342e..5d5d562 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
@@ -18,9 +18,10 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
+import com.android.systemui.statusbar.pipeline.dagger.AirplaneTableLog
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
@@ -46,7 +47,7 @@
@Inject
constructor(
interactor: AirplaneModeInteractor,
- logger: ConnectivityPipelineLogger,
+ @AirplaneTableLog logger: TableLogBuffer,
@Application private val scope: CoroutineScope,
) : AirplaneModeViewModel {
override val isAirplaneModeIconVisible: StateFlow<Boolean> =
@@ -56,6 +57,11 @@
isAirplaneMode && !isAirplaneIconForceHidden
}
.distinctUntilChanged()
- .logOutputChange(logger, "isAirplaneModeIconVisible")
+ .logDiffsForTable(
+ logger,
+ columnPrefix = "",
+ columnName = "isAirplaneModeIconVisible",
+ initialValue = false,
+ )
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileInputLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileInputLog.kt
new file mode 100644
index 0000000..d1aa79e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileInputLog.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.dagger
+
+import javax.inject.Qualifier
+
+/** Logs for inputs into the mobile pipeline. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class MobileInputLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/SharedConnectivityInputLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/SharedConnectivityInputLog.kt
new file mode 100644
index 0000000..5face22
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/SharedConnectivityInputLog.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.dagger
+
+import javax.inject.Qualifier
+
+/** Logs for connectivity-related inputs that are shared across wifi, mobile, etc. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class SharedConnectivityInputLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 60de1a3..4464751 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -19,8 +19,10 @@
import android.net.wifi.WifiManager
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBufferFactory
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepositoryImpl
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
@@ -107,6 +109,13 @@
@Provides
@SysUISingleton
+ @WifiInputLog
+ fun provideWifiInputLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("WifiInputLog", 50)
+ }
+
+ @Provides
+ @SysUISingleton
@WifiTableLog
fun provideWifiTableLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
return factory.create("WifiTableLog", 100)
@@ -121,9 +130,23 @@
@Provides
@SysUISingleton
+ @SharedConnectivityInputLog
+ fun provideSharedConnectivityTableLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("SharedConnectivityInputLog", 30)
+ }
+
+ @Provides
+ @SysUISingleton
@MobileSummaryLog
fun provideMobileSummaryLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
return factory.create("MobileSummaryLog", 100)
}
+
+ @Provides
+ @SysUISingleton
+ @MobileInputLog
+ fun provideMobileInputLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("MobileInputLog", 100)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiInputLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiInputLog.kt
new file mode 100644
index 0000000..6db6944
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiInputLog.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.dagger
+
+import javax.inject.Qualifier
+
+/** Wifi logs for inputs into the wifi pipeline. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class WifiInputLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
index 5769f90..bb3b9b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
@@ -31,7 +31,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -57,7 +57,7 @@
broadcastDispatcher: BroadcastDispatcher,
private val carrierConfigManager: CarrierConfigManager,
dumpManager: DumpManager,
- logger: ConnectivityPipelineLogger,
+ logger: MobileInputLogger,
@Application scope: CoroutineScope,
) : Dumpable {
private var isListening = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index dcce0ea..96b96f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -47,8 +47,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -85,7 +85,7 @@
broadcastDispatcher: BroadcastDispatcher,
private val mobileMappingsProxy: MobileMappingsProxy,
bgDispatcher: CoroutineDispatcher,
- logger: ConnectivityPipelineLogger,
+ logger: MobileInputLogger,
override val tableLogBuffer: TableLogBuffer,
scope: CoroutineScope,
) : MobileConnectionRepository {
@@ -291,7 +291,7 @@
private val broadcastDispatcher: BroadcastDispatcher,
private val context: Context,
private val telephonyManager: TelephonyManager,
- private val logger: ConnectivityPipelineLogger,
+ private val logger: MobileInputLogger,
private val carrierConfigRepository: CarrierConfigRepository,
private val mobileMappingsProxy: MobileMappingsProxy,
@Background private val bgDispatcher: CoroutineDispatcher,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 73ce5e6..b3d5b1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -49,9 +49,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.util.kotlin.pairwise
@@ -84,7 +83,7 @@
private val connectivityManager: ConnectivityManager,
private val subscriptionManager: SubscriptionManager,
private val telephonyManager: TelephonyManager,
- private val logger: ConnectivityPipelineLogger,
+ private val logger: MobileInputLogger,
@MobileSummaryLog private val tableLogger: TableLogBuffer,
mobileMappingsProxy: MobileMappingsProxy,
broadcastDispatcher: BroadcastDispatcher,
@@ -222,13 +221,13 @@
private val carrierConfigChangedEvent =
broadcastDispatcher
.broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED))
- .logInputChange(logger, "ACTION_CARRIER_CONFIG_CHANGED")
+ .onEach { logger.logActionCarrierConfigChanged() }
override val defaultDataSubRatConfig: StateFlow<Config> =
merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent)
.mapLatest { Config.readConfig(context) }
.distinctUntilChanged()
- .logInputChange(logger, "defaultDataSubRatConfig")
+ .onEach { logger.logDefaultDataSubRatConfig(it) }
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
@@ -239,13 +238,13 @@
defaultDataSubRatConfig
.map { mobileMappingsProxy.mapIconSets(it) }
.distinctUntilChanged()
- .logInputChange(logger, "defaultMobileIconMapping")
+ .onEach { logger.logDefaultMobileIconMapping(it) }
override val defaultMobileIconGroup: Flow<MobileIconGroup> =
defaultDataSubRatConfig
.map { mobileMappingsProxy.getDefaultIcons(it) }
.distinctUntilChanged()
- .logInputChange(logger, "defaultMobileIconGroup")
+ .onEach { logger.logDefaultMobileIconGroup(it) }
override fun getRepoForSubId(subId: Int): FullMobileConnectionRepository {
if (!isValidSubId(subId)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 5a2e11e..142c372 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -30,7 +30,6 @@
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.util.CarrierConfigTracker
@@ -111,7 +110,6 @@
constructor(
private val mobileConnectionsRepo: MobileConnectionsRepository,
private val carrierConfigTracker: CarrierConfigTracker,
- private val logger: ConnectivityPipelineLogger,
@MobileSummaryLog private val tableLogger: TableLogBuffer,
connectivityRepository: ConnectivityRepository,
userSetupRepo: UserSetupRepository,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt
new file mode 100644
index 0000000..3cbd2b7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.shared
+
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.telephony.ServiceState
+import android.telephony.SignalStrength
+import android.telephony.TelephonyDisplayInfo
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.MobileInputLog
+import com.android.systemui.statusbar.pipeline.shared.LoggerHelper
+import javax.inject.Inject
+
+/** Logs for inputs into the mobile pipeline. */
+@SysUISingleton
+class MobileInputLogger
+@Inject
+constructor(
+ @MobileInputLog private val buffer: LogBuffer,
+) {
+ fun logOnCapabilitiesChanged(
+ network: Network,
+ networkCapabilities: NetworkCapabilities,
+ isDefaultNetworkCallback: Boolean,
+ ) {
+ LoggerHelper.logOnCapabilitiesChanged(
+ buffer,
+ TAG,
+ network,
+ networkCapabilities,
+ isDefaultNetworkCallback,
+ )
+ }
+
+ fun logOnLost(network: Network) {
+ LoggerHelper.logOnLost(buffer, TAG, network)
+ }
+
+ fun logOnServiceStateChanged(serviceState: ServiceState, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ bool1 = serviceState.isEmergencyOnly
+ bool2 = serviceState.roaming
+ str1 = serviceState.operatorAlphaShort
+ },
+ {
+ "onServiceStateChanged: subId=$int1 emergencyOnly=$bool1 roaming=$bool2" +
+ " operator=$str1"
+ }
+ )
+ }
+
+ fun logOnSignalStrengthsChanged(signalStrength: SignalStrength, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ str1 = signalStrength.toString()
+ },
+ { "onSignalStrengthsChanged: subId=$int1 strengths=$str1" }
+ )
+ }
+
+ fun logOnDataConnectionStateChanged(dataState: Int, networkType: Int, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ int2 = dataState
+ str1 = networkType.toString()
+ },
+ { "onDataConnectionStateChanged: subId=$int1 dataState=$int2 networkType=$str1" },
+ )
+ }
+
+ fun logOnDataActivity(direction: Int, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ int2 = direction
+ },
+ { "onDataActivity: subId=$int1 direction=$int2" },
+ )
+ }
+
+ fun logOnCarrierNetworkChange(active: Boolean, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ bool1 = active
+ },
+ { "onCarrierNetworkChange: subId=$int1 active=$bool1" },
+ )
+ }
+
+ fun logOnDisplayInfoChanged(displayInfo: TelephonyDisplayInfo, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ str1 = displayInfo.toString()
+ },
+ { "onDisplayInfoChanged: subId=$int1 displayInfo=$str1" },
+ )
+ }
+
+ fun logUiAdapterSubIdsUpdated(subs: List<Int>) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = subs.toString() },
+ { "Sub IDs in MobileUiAdapter updated internally: $str1" },
+ )
+ }
+
+ fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = subs.toString() },
+ { "Sub IDs in MobileUiAdapter being sent to icon controller: $str1" },
+ )
+ }
+
+ fun logCarrierConfigChanged(subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { int1 = subId },
+ { "onCarrierConfigChanged: subId=$int1" },
+ )
+ }
+
+ fun logOnDataEnabledChanged(enabled: Boolean, subId: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = subId
+ bool1 = enabled
+ },
+ { "onDataEnabledChanged: subId=$int1 enabled=$bool1" },
+ )
+ }
+
+ fun logActionCarrierConfigChanged() {
+ buffer.log(TAG, LogLevel.INFO, {}, { "Intent received: ACTION_CARRIER_CONFIG_CHANGED" })
+ }
+
+ fun logDefaultDataSubRatConfig(config: MobileMappings.Config) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = config.toString() },
+ { "defaultDataSubRatConfig: $str1" }
+ )
+ }
+
+ fun logDefaultMobileIconMapping(mapping: Map<String, SignalIcon.MobileIconGroup>) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { str1 = mapping.toString() },
+ { "defaultMobileIconMapping: $str1" }
+ )
+ }
+
+ fun logDefaultMobileIconGroup(group: SignalIcon.MobileIconGroup) {
+ buffer.log(TAG, LogLevel.INFO, { str1 = group.name }, { "defaultMobileIconGroup: $str1" })
+ }
+}
+
+private const val TAG = "MobileInputLog"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
index ef75713..da63ab1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
@@ -22,8 +22,8 @@
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -55,7 +55,7 @@
interactor: MobileIconsInteractor,
private val iconController: StatusBarIconController,
private val iconsViewModelFactory: MobileIconsViewModel.Factory,
- private val logger: ConnectivityPipelineLogger,
+ private val logger: MobileInputLogger,
@Application private val scope: CoroutineScope,
private val statusBarPipelineFlags: StatusBarPipelineFlags,
) : CoreStartable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index 185b668..8cb52af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -25,7 +25,6 @@
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow
@@ -42,7 +41,6 @@
val subscriptionIdsFlow: StateFlow<List<Int>>,
private val interactor: MobileIconsInteractor,
private val airplaneModeInteractor: AirplaneModeInteractor,
- private val logger: ConnectivityPipelineLogger,
private val constants: ConnectivityConstants,
@Application private val scope: CoroutineScope,
private val statusBarPipelineFlags: StatusBarPipelineFlags,
@@ -83,7 +81,6 @@
constructor(
private val interactor: MobileIconsInteractor,
private val airplaneModeInteractor: AirplaneModeInteractor,
- private val logger: ConnectivityPipelineLogger,
private val constants: ConnectivityConstants,
@Application private val scope: CoroutineScope,
private val statusBarPipelineFlags: StatusBarPipelineFlags,
@@ -93,7 +90,6 @@
subscriptionIdsFlow,
interactor,
airplaneModeInteractor,
- logger,
constants,
scope,
statusBarPipelineFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt
index 0c9b86c..0fe5329 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt
@@ -22,7 +22,6 @@
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
import java.io.PrintWriter
import javax.inject.Inject
@@ -40,7 +39,7 @@
telephonyManager: TelephonyManager,
) : Dumpable {
init {
- dumpManager.registerNormalDumpable("${SB_LOGGING_TAG}Constants", this)
+ dumpManager.registerNormalDumpable("ConnectivityConstants", this)
}
/** True if this device has the capability for data connections and false otherwise. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
new file mode 100644
index 0000000..95548b8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.SharedConnectivityInputLog
+import javax.inject.Inject
+
+/** Logs for connectivity-related inputs that are shared across wifi, mobile, etc. */
+@SysUISingleton
+class ConnectivityInputLogger
+@Inject
+constructor(
+ @SharedConnectivityInputLog private val buffer: LogBuffer,
+) {
+ fun logTuningChanged(tuningList: String?) {
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = tuningList }, { "onTuningChanged: $str1" })
+ }
+}
+
+private const val TAG = "ConnectivityInputLogger"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
deleted file mode 100644
index 45036969..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.shared
-
-import android.net.Network
-import android.net.NetworkCapabilities
-import android.telephony.ServiceState
-import android.telephony.SignalStrength
-import android.telephony.TelephonyDisplayInfo
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.dagger.StatusBarConnectivityLog
-import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.toString
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.onEach
-
-@SysUISingleton
-class ConnectivityPipelineLogger
-@Inject
-constructor(
- @StatusBarConnectivityLog private val buffer: LogBuffer,
-) {
- /**
- * Logs a change in one of the **raw inputs** to the connectivity pipeline.
- *
- * Use this method for inputs that don't have any extra information besides their callback name.
- */
- fun logInputChange(callbackName: String) {
- buffer.log(SB_LOGGING_TAG, LogLevel.INFO, { str1 = callbackName }, { "Input: $str1" })
- }
-
- /** Logs a change in one of the **raw inputs** to the connectivity pipeline. */
- fun logInputChange(callbackName: String, changeInfo: String?) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- str1 = callbackName
- str2 = changeInfo
- },
- { "Input: $str1: $str2" }
- )
- }
-
- /** Logs a **data transformation** that we performed within the connectivity pipeline. */
- fun logTransformation(transformationName: String, oldValue: Any?, newValue: Any?) {
- if (oldValue == newValue) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- str1 = transformationName
- str2 = oldValue.toString()
- },
- { "Transform: $str1: $str2 (transformation didn't change it)" }
- )
- } else {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- str1 = transformationName
- str2 = oldValue.toString()
- str3 = newValue.toString()
- },
- { "Transform: $str1: $str2 -> $str3" }
- )
- }
- }
-
- /** Logs a change in one of the **outputs** to the connectivity pipeline. */
- fun logOutputChange(outputParamName: String, changeInfo: String) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- str1 = outputParamName
- str2 = changeInfo
- },
- { "Output: $str1: $str2" }
- )
- }
-
- fun logOnCapabilitiesChanged(
- network: Network,
- networkCapabilities: NetworkCapabilities,
- isDefaultNetworkCallback: Boolean,
- ) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- bool1 = isDefaultNetworkCallback
- int1 = network.getNetId()
- str1 = networkCapabilities.toString()
- },
- { "onCapabilitiesChanged[default=$bool1]: net=$int1 capabilities=$str1" }
- )
- }
-
- fun logOnLost(network: Network) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- { int1 = network.getNetId() },
- { "onLost: net=$int1" }
- )
- }
-
- fun logOnServiceStateChanged(serviceState: ServiceState, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- bool1 = serviceState.isEmergencyOnly
- bool2 = serviceState.roaming
- str1 = serviceState.operatorAlphaShort
- },
- {
- "onServiceStateChanged: subId=$int1 emergencyOnly=$bool1 roaming=$bool2" +
- " operator=$str1"
- }
- )
- }
-
- fun logOnSignalStrengthsChanged(signalStrength: SignalStrength, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- str1 = signalStrength.toString()
- },
- { "onSignalStrengthsChanged: subId=$int1 strengths=$str1" }
- )
- }
-
- fun logOnDataConnectionStateChanged(dataState: Int, networkType: Int, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- int2 = dataState
- str1 = networkType.toString()
- },
- { "onDataConnectionStateChanged: subId=$int1 dataState=$int2 networkType=$str1" },
- )
- }
-
- fun logOnDataActivity(direction: Int, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- int2 = direction
- },
- { "onDataActivity: subId=$int1 direction=$int2" },
- )
- }
-
- fun logOnCarrierNetworkChange(active: Boolean, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- bool1 = active
- },
- { "onCarrierNetworkChange: subId=$int1 active=$bool1" },
- )
- }
-
- fun logOnDisplayInfoChanged(displayInfo: TelephonyDisplayInfo, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- str1 = displayInfo.toString()
- },
- { "onDisplayInfoChanged: subId=$int1 displayInfo=$str1" },
- )
- }
-
- // TODO(b/238425913): We should split this class into mobile-specific and wifi-specific loggers.
-
- fun logUiAdapterSubIdsUpdated(subs: List<Int>) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- { str1 = subs.toString() },
- { "Sub IDs in MobileUiAdapter updated internally: $str1" },
- )
- }
-
- fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- { str1 = subs.toString() },
- { "Sub IDs in MobileUiAdapter being sent to icon controller: $str1" },
- )
- }
-
- fun logCarrierConfigChanged(subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- { int1 = subId },
- { "onCarrierConfigChanged: subId=$int1" },
- )
- }
-
- fun logOnDataEnabledChanged(enabled: Boolean, subId: Int) {
- buffer.log(
- SB_LOGGING_TAG,
- LogLevel.INFO,
- {
- int1 = subId
- bool1 = enabled
- },
- { "onDataEnabledChanged: subId=$int1 enabled=$bool1" },
- )
- }
-
- companion object {
- const val SB_LOGGING_TAG = "SbConnectivity"
-
- /** Log a change in one of the **inputs** to the connectivity pipeline. */
- fun Flow<Unit>.logInputChange(
- logger: ConnectivityPipelineLogger,
- inputParamName: String,
- ): Flow<Unit> {
- return this.onEach { logger.logInputChange(inputParamName) }
- }
-
- /**
- * Log a change in one of the **inputs** to the connectivity pipeline.
- *
- * @param prettyPrint an optional function to transform the value into a readable string.
- * [toString] is used if no custom function is provided.
- */
- fun <T> Flow<T>.logInputChange(
- logger: ConnectivityPipelineLogger,
- inputParamName: String,
- prettyPrint: (T) -> String = { it.toString() }
- ): Flow<T> {
- return this.onEach { logger.logInputChange(inputParamName, prettyPrint(it)) }
- }
-
- /**
- * Log a change in one of the **outputs** to the connectivity pipeline.
- *
- * @param prettyPrint an optional function to transform the value into a readable string.
- * [toString] is used if no custom function is provided.
- */
- fun <T> Flow<T>.logOutputChange(
- logger: ConnectivityPipelineLogger,
- outputParamName: String,
- prettyPrint: (T) -> String = { it.toString() }
- ): Flow<T> {
- return this.onEach { logger.logOutputChange(outputParamName, prettyPrint(it)) }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
new file mode 100644
index 0000000..6f29e33
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared
+
+import android.net.Network
+import android.net.NetworkCapabilities
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+
+/** Helper object for logs that are shared between wifi and mobile. */
+object LoggerHelper {
+ fun logOnCapabilitiesChanged(
+ buffer: LogBuffer,
+ tag: String,
+ network: Network,
+ networkCapabilities: NetworkCapabilities,
+ isDefaultNetworkCallback: Boolean,
+ ) {
+ buffer.log(
+ tag,
+ LogLevel.INFO,
+ {
+ bool1 = isDefaultNetworkCallback
+ int1 = network.getNetId()
+ str1 = networkCapabilities.toString()
+ },
+ { "onCapabilitiesChanged[default=$bool1]: net=$int1 capabilities=$str1" }
+ )
+ }
+
+ fun logOnLost(buffer: LogBuffer, tag: String, network: Network) {
+ buffer.log(tag, LogLevel.INFO, { int1 = network.getNetId() }, { "onLost: net=$int1" })
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
index 45c6d46..5d9ba018 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
@@ -26,8 +26,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.phone.StatusBarIconController
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityInputLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
import com.android.systemui.tuner.TunerService
@@ -45,59 +44,61 @@
* types of connectivity (wifi, mobile, ethernet, etc.)
*/
interface ConnectivityRepository {
- /**
- * Observable for the current set of connectivity icons that should be force-hidden.
- */
+ /** Observable for the current set of connectivity icons that should be force-hidden. */
val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>>
}
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
-class ConnectivityRepositoryImpl @Inject constructor(
+class ConnectivityRepositoryImpl
+@Inject
+constructor(
private val connectivitySlots: ConnectivitySlots,
context: Context,
dumpManager: DumpManager,
- logger: ConnectivityPipelineLogger,
+ logger: ConnectivityInputLogger,
@Application scope: CoroutineScope,
tunerService: TunerService,
) : ConnectivityRepository, Dumpable {
init {
- dumpManager.registerDumpable("${SB_LOGGING_TAG}Repository", this)
+ dumpManager.registerDumpable("ConnectivityRepository", this)
}
// The default set of hidden icons to use if we don't get any from [TunerService].
private val defaultHiddenIcons: Set<ConnectivitySlot> =
- context.resources.getStringArray(DEFAULT_HIDDEN_ICONS_RESOURCE)
- .asList()
- .toSlotSet(connectivitySlots)
+ context.resources
+ .getStringArray(DEFAULT_HIDDEN_ICONS_RESOURCE)
+ .asList()
+ .toSlotSet(connectivitySlots)
- override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> = conflatedCallbackFlow {
- val callback = object : TunerService.Tunable {
- override fun onTuningChanged(key: String, newHideList: String?) {
- if (key != HIDDEN_ICONS_TUNABLE_KEY) {
- return
- }
- logger.logInputChange("onTuningChanged", newHideList)
+ override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> =
+ conflatedCallbackFlow {
+ val callback =
+ object : TunerService.Tunable {
+ override fun onTuningChanged(key: String, newHideList: String?) {
+ if (key != HIDDEN_ICONS_TUNABLE_KEY) {
+ return
+ }
+ logger.logTuningChanged(newHideList)
- val outputList = newHideList?.split(",")?.toSlotSet(connectivitySlots)
- ?: defaultHiddenIcons
- trySend(outputList)
+ val outputList =
+ newHideList?.split(",")?.toSlotSet(connectivitySlots)
+ ?: defaultHiddenIcons
+ trySend(outputList)
+ }
+ }
+ tunerService.addTunable(callback, HIDDEN_ICONS_TUNABLE_KEY)
+
+ awaitClose { tunerService.removeTunable(callback) }
}
- }
- tunerService.addTunable(callback, HIDDEN_ICONS_TUNABLE_KEY)
-
- awaitClose { tunerService.removeTunable(callback) }
- }
- .stateIn(
- scope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = defaultHiddenIcons
- )
+ .stateIn(
+ scope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = defaultHiddenIcons
+ )
override fun dump(pw: PrintWriter, args: Array<out String>) {
- pw.apply {
- println("defaultHiddenIcons=$defaultHiddenIcons")
- }
+ pw.apply { println("defaultHiddenIcons=$defaultHiddenIcons") }
}
companion object {
@@ -111,8 +112,7 @@
private fun List<String>.toSlotSet(
connectivitySlots: ConnectivitySlots
): Set<ConnectivitySlot> {
- return this
- .filter { it.isNotBlank() }
+ return this.filter { it.isNotBlank() }
.mapNotNull { connectivitySlots.getSlotFromName(it) }
.toSet()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index 7b486c1..ee58160 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -39,12 +39,11 @@
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -58,6 +57,7 @@
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
/** Real implementation of [WifiRepository]. */
@@ -70,7 +70,7 @@
constructor(
broadcastDispatcher: BroadcastDispatcher,
connectivityManager: ConnectivityManager,
- logger: ConnectivityPipelineLogger,
+ logger: WifiInputLogger,
@WifiTableLog wifiTableLogBuffer: TableLogBuffer,
@Main mainExecutor: Executor,
@Application scope: CoroutineScope,
@@ -80,7 +80,7 @@
private val wifiStateChangeEvents: Flow<Unit> =
broadcastDispatcher
.broadcastFlow(IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION))
- .logInputChange(logger, "WIFI_STATE_CHANGED_ACTION intent")
+ .onEach { logger.logIntent("WIFI_STATE_CHANGED_ACTION") }
private val wifiNetworkChangeEvents: MutableSharedFlow<Unit> =
MutableSharedFlow(extraBufferCapacity = 1)
@@ -173,11 +173,6 @@
networkCapabilities,
wifiManager,
)
- logger.logTransformation(
- WIFI_NETWORK_CALLBACK_NAME,
- oldValue = currentWifi,
- newValue = wifiNetworkModel,
- )
currentWifi = wifiNetworkModel
trySend(wifiNetworkModel)
}
@@ -194,11 +189,6 @@
wifi.networkId == network.getNetId()
) {
val newNetworkModel = WifiNetworkModel.Inactive
- logger.logTransformation(
- WIFI_NETWORK_CALLBACK_NAME,
- oldValue = wifi,
- newValue = newNetworkModel,
- )
currentWifi = newNetworkModel
trySend(newNetworkModel)
}
@@ -228,7 +218,7 @@
override val wifiActivity: StateFlow<DataActivityModel> =
conflatedCallbackFlow {
val callback = TrafficStateCallback { state ->
- logger.logInputChange("onTrafficStateChange", prettyPrintActivity(state))
+ logger.logActivity(prettyPrintActivity(state))
trySend(state.toWifiDataActivityModel())
}
wifiManager.registerTrafficStateCallback(mainExecutor, callback)
@@ -336,8 +326,6 @@
.addTransportType(TRANSPORT_CELLULAR)
.build()
- private const val WIFI_NETWORK_CALLBACK_NAME = "wifiNetworkModel"
-
private const val CARRIER_MERGED_INVALID_SUB_ID_REASON =
"Wifi network was carrier merged but had invalid sub ID"
}
@@ -348,7 +336,7 @@
constructor(
private val broadcastDispatcher: BroadcastDispatcher,
private val connectivityManager: ConnectivityManager,
- private val logger: ConnectivityPipelineLogger,
+ private val logger: WifiInputLogger,
@WifiTableLog private val wifiTableLogBuffer: TableLogBuffer,
@Main private val mainExecutor: Executor,
@Application private val scope: CoroutineScope,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
index 4f7fe28..8bea772 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
@@ -21,7 +21,6 @@
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
import java.io.PrintWriter
import javax.inject.Inject
@@ -30,12 +29,14 @@
* logging purposes.
*/
@SysUISingleton
-class WifiConstants @Inject constructor(
- context: Context,
- dumpManager: DumpManager,
+class WifiConstants
+@Inject
+constructor(
+ context: Context,
+ dumpManager: DumpManager,
) : Dumpable {
init {
- dumpManager.registerDumpable("${SB_LOGGING_TAG}WifiConstants", this)
+ dumpManager.registerNormalDumpable("WifiConstants", this)
}
/** True if we should always show the wifi icon when wifi is enabled and false otherwise. */
@@ -43,8 +44,6 @@
context.resources.getBoolean(R.bool.config_showWifiIndicatorWhenEnabled)
override fun dump(pw: PrintWriter, args: Array<out String>) {
- pw.apply {
- println("alwaysShowIconIfEnabled=$alwaysShowIconIfEnabled")
- }
+ pw.apply { println("alwaysShowIconIfEnabled=$alwaysShowIconIfEnabled") }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
new file mode 100644
index 0000000..a32e475
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.shared
+
+import android.net.Network
+import android.net.NetworkCapabilities
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.WifiInputLog
+import com.android.systemui.statusbar.pipeline.shared.LoggerHelper
+import javax.inject.Inject
+
+/**
+ * Logger for all the wifi-related inputs (intents, callbacks, etc.) that the wifi repo receives.
+ */
+@SysUISingleton
+class WifiInputLogger
+@Inject
+constructor(
+ @WifiInputLog val buffer: LogBuffer,
+) {
+ fun logOnCapabilitiesChanged(
+ network: Network,
+ networkCapabilities: NetworkCapabilities,
+ isDefaultNetworkCallback: Boolean,
+ ) {
+ LoggerHelper.logOnCapabilitiesChanged(
+ buffer,
+ TAG,
+ network,
+ networkCapabilities,
+ isDefaultNetworkCallback,
+ )
+ }
+
+ fun logOnLost(network: Network) {
+ LoggerHelper.logOnLost(buffer, TAG, network)
+ }
+
+ fun logIntent(intentName: String) {
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = intentName }, { "Intent received: $str1" })
+ }
+
+ fun logActivity(activity: String) {
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = activity }, { "Activity: $str1" })
+ }
+}
+
+private const val TAG = "WifiInputLog"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
index 0f5ff91..1057231 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -34,8 +34,6 @@
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
@@ -69,7 +67,6 @@
airplaneModeViewModel: AirplaneModeViewModel,
connectivityConstants: ConnectivityConstants,
private val context: Context,
- logger: ConnectivityPipelineLogger,
@WifiTableLog wifiTableLogBuffer: TableLogBuffer,
interactor: WifiInteractor,
@Application private val scope: CoroutineScope,
@@ -143,29 +140,35 @@
)
/** The wifi activity status. Null if we shouldn't display the activity status. */
- private val activity: Flow<DataActivityModel?> =
+ private val activity: Flow<DataActivityModel> = run {
+ val default = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
if (!connectivityConstants.shouldShowActivityConfig) {
- flowOf(null)
+ flowOf(default)
} else {
combine(interactor.activity, interactor.ssid) { activity, ssid ->
when (ssid) {
- null -> null
+ null -> default
else -> activity
}
}
}
.distinctUntilChanged()
- .logOutputChange(logger, "activity")
- .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null)
+ .logDiffsForTable(
+ wifiTableLogBuffer,
+ columnPrefix = "VM.activity",
+ initialValue = default,
+ )
+ .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = default)
+ }
private val isActivityInViewVisible: Flow<Boolean> =
activity
- .map { it?.hasActivityIn == true }
+ .map { it.hasActivityIn }
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
private val isActivityOutViewVisible: Flow<Boolean> =
activity
- .map { it?.hasActivityOut == true }
+ .map { it.hasActivityOut }
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
private val isActivityContainerVisible: Flow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index 1ae1eae..8929e02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -56,7 +56,7 @@
/**
* Whether the bouncer (PIN/password entry) is currently visible.
*/
- boolean isBouncerShowing();
+ boolean isPrimaryBouncerShowing();
/**
* If swiping up will unlock without asking for a password.
@@ -196,7 +196,7 @@
/** **/
default void notifyKeyguardState(boolean showing, boolean occluded) {}
/** **/
- default void notifyBouncerShowing(boolean showing) {}
+ default void notifyPrimaryBouncerShowing(boolean showing) {}
/**
* Updates the keyguard state to reflect that it's in the process of being dismissed, either by
@@ -244,7 +244,7 @@
/**
* Called when the bouncer (PIN/password entry) is shown or hidden.
*/
- default void onBouncerShowingChanged() {}
+ default void onPrimaryBouncerShowingChanged() {}
/**
* Triggered when the device was just unlocked and the lock screen is being dismissed.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 9ad36fd5..805368c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -65,7 +65,7 @@
private boolean mCanDismissLockScreen;
private boolean mShowing;
- private boolean mBouncerShowing;
+ private boolean mPrimaryBouncerShowing;
private boolean mSecure;
private boolean mOccluded;
@@ -157,8 +157,8 @@
}
@Override
- public boolean isBouncerShowing() {
- return mBouncerShowing;
+ public boolean isPrimaryBouncerShowing() {
+ return mPrimaryBouncerShowing;
}
@Override
@@ -339,11 +339,11 @@
}
@Override
- public void notifyBouncerShowing(boolean showing) {
- if (mBouncerShowing != showing) {
- mBouncerShowing = showing;
+ public void notifyPrimaryBouncerShowing(boolean showing) {
+ if (mPrimaryBouncerShowing != showing) {
+ mPrimaryBouncerShowing = showing;
- new ArrayList<>(mCallbacks).forEach(Callback::onBouncerShowingChanged);
+ new ArrayList<>(mCallbacks).forEach(Callback::onPrimaryBouncerShowingChanged);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
index c1f0c58..39dda8c 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
+++ b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
@@ -55,15 +55,15 @@
Pair.create("error_container", MDC.errorContainer),
Pair.create("on_error_container", MDC.onErrorContainer),
Pair.create("primary_fixed", MDC.primaryFixed),
- Pair.create("primary_fixed_darker", MDC.primaryFixedDarker),
+ Pair.create("primary_fixed_dim", MDC.primaryFixedDim),
Pair.create("on_primary_fixed", MDC.onPrimaryFixed),
Pair.create("on_primary_fixed_variant", MDC.onPrimaryFixedVariant),
Pair.create("secondary_fixed", MDC.secondaryFixed),
- Pair.create("secondary_fixed_darker", MDC.secondaryFixedDarker),
+ Pair.create("secondary_fixed_dim", MDC.secondaryFixedDim),
Pair.create("on_secondary_fixed", MDC.onSecondaryFixed),
Pair.create("on_secondary_fixed_variant", MDC.onSecondaryFixedVariant),
Pair.create("tertiary_fixed", MDC.tertiaryFixed),
- Pair.create("tertiary_fixed_darker", MDC.tertiaryFixedDarker),
+ Pair.create("tertiary_fixed_dim", MDC.tertiaryFixedDim),
Pair.create("on_tertiary_fixed", MDC.onTertiaryFixed),
Pair.create("on_tertiary_fixed_variant", MDC.onTertiaryFixedVariant),
Pair.create("control_activated", MDC.controlActivated),
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
index badeb27..81fef7a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
@@ -31,6 +31,7 @@
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_WAKE
import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
@@ -338,6 +339,70 @@
}
@Test
+ fun isWakeupForceDismissKeyguard_singleValue() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN lift is considered an unlock intent
+ secureSettings.putStringForUser(ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
+ PowerManager.WAKE_REASON_LIFT.toString(), currentUser)
+ updateSetting(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD
+ ))
+
+ // THEN only WAKE_REASON_LIFT is considered an unlock intent
+ for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
+ if (wakeReason == PowerManager.WAKE_REASON_LIFT) {
+ assertTrue(activeUnlockConfig.shouldWakeupForceDismissKeyguard(wakeReason))
+ } else {
+ assertFalse(activeUnlockConfig.shouldWakeupForceDismissKeyguard(wakeReason))
+ }
+ }
+ }
+
+ @Test
+ fun isWakeupForceDismissKeyguard_emptyValues() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN lift and tap are considered an unlock intent
+ secureSettings.putStringForUser(ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
+ " ", currentUser)
+ updateSetting(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD
+ ))
+
+ // THEN no wake up gestures are considered an unlock intent
+ for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
+ assertFalse(activeUnlockConfig.shouldWakeupForceDismissKeyguard(wakeReason))
+ }
+ }
+
+ @Test
+ fun isWakeupForceDismissKeyguard_multiValue() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN lift and tap are considered an unlock intent
+ secureSettings.putStringForUser(ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD,
+ PowerManager.WAKE_REASON_LIFT.toString() +
+ "|" +
+ PowerManager.WAKE_REASON_TAP.toString(),
+ currentUser
+ )
+ updateSetting(secureSettings.getUriFor(
+ ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD
+ ))
+
+ // THEN WAKE_REASON_LIFT and WAKE_REASON TAP are considered an unlock intent
+ for (wakeReason in 0..WAKE_REASON_BIOMETRIC) {
+ if (wakeReason == PowerManager.WAKE_REASON_LIFT ||
+ wakeReason == PowerManager.WAKE_REASON_TAP) {
+ assertTrue(activeUnlockConfig.shouldWakeupForceDismissKeyguard(wakeReason))
+ } else {
+ assertFalse(activeUnlockConfig.shouldWakeupForceDismissKeyguard(wakeReason))
+ }
+ }
+ }
+
+ @Test
fun dump_onUnlockIntentWhenBiometricEnrolled_invalidNum_noArrayOutOfBoundsException() {
// GIVEN an invalid input (-1)
secureSettings.putStringForUser(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index f7fec80..480b8f9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -23,6 +23,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -85,6 +86,7 @@
@Mock private lateinit var transitionRepository: KeyguardTransitionRepository
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var repository: FakeKeyguardRepository
+ private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
@Mock private lateinit var smallLogBuffer: LogBuffer
@Mock private lateinit var largeLogBuffer: LogBuffer
private lateinit var underTest: ClockEventController
@@ -103,11 +105,15 @@
whenever(largeClockEvents.tickRate).thenReturn(ClockTickRate.PER_MINUTE)
repository = FakeKeyguardRepository()
+ bouncerRepository = FakeKeyguardBouncerRepository()
underTest = ClockEventController(
- KeyguardInteractor(repository = repository,
- commandQueue = commandQueue,
- featureFlags = featureFlags),
+ KeyguardInteractor(
+ repository = repository,
+ commandQueue = commandQueue,
+ featureFlags = featureFlags,
+ bouncerRepository = bouncerRepository,
+ ),
KeyguardTransitionInteractor(repository = transitionRepository),
broadcastDispatcher,
batteryController,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index ccc4e4a..a5f90f8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -241,7 +241,7 @@
mController.init();
verify(mClockRegistry).registerClockChangeListener(listenerArgumentCaptor.capture());
- listenerArgumentCaptor.getValue().onClockChanged();
+ listenerArgumentCaptor.getValue().onCurrentClockChanged();
verify(mView, times(2)).setClock(mClockController, StatusBarState.SHADE);
verify(mClockEventController, times(2)).setClock(mClockController);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 841ec4b..9fe7506 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -909,6 +909,25 @@
}
@Test
+ public void noFpListeningWhenKeyguardIsOccluded_unlessAlternateBouncerShowing() {
+ // GIVEN device is awake but occluded
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+ mKeyguardUpdateMonitor.setKeyguardShowing(false, true);
+
+ // THEN fingerprint shouldn't listen
+ assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isFalse();
+ verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyInt(), anyInt());
+
+ // WHEN alternate bouncer is shown
+ mKeyguardUpdateMonitor.setAlternateBouncerShowing(true);
+
+ // THEN make sure FP listening begins
+ verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
+ anyInt());
+ }
+
+ @Test
public void testTriesToAuthenticate_whenTrustOnAgentKeyguard_ifBypass() {
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
@@ -2006,7 +2025,6 @@
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
-
@Test
public void testOnTrustGrantedForCurrentUser_dismissKeyguardRequested_deviceInteractive() {
// GIVEN device is interactive
@@ -2432,6 +2450,56 @@
assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
}
+ @Test
+ public void unfoldWakeup_requestActiveUnlock_forceDismissKeyguard()
+ throws RemoteException {
+ // GIVEN shouldTriggerActiveUnlock
+ keyguardIsVisible();
+ when(mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())).thenReturn(true);
+
+ // GIVEN active unlock triggers on wakeup
+ when(mActiveUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE))
+ .thenReturn(true);
+
+ // GIVEN an unfold should force dismiss the keyguard
+ when(mActiveUnlockConfig.shouldWakeupForceDismissKeyguard(
+ PowerManager.WAKE_REASON_UNFOLD_DEVICE)).thenReturn(true);
+
+ // WHEN device wakes up from an unfold
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNFOLD_DEVICE);
+ mTestableLooper.processAllMessages();
+
+ // THEN request unlock with a keyguard dismissal
+ verify(mTrustManager).reportUserRequestedUnlock(eq(KeyguardUpdateMonitor.getCurrentUser()),
+ eq(true));
+ }
+
+ @Test
+ public void unfoldWakeup_requestActiveUnlock_noDismissKeyguard()
+ throws RemoteException {
+ // GIVEN shouldTriggerActiveUnlock on wake from UNFOLD_DEVICE
+ keyguardIsVisible();
+ when(mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())).thenReturn(true);
+
+ // GIVEN active unlock triggers on wakeup
+ when(mActiveUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE))
+ .thenReturn(true);
+
+ // GIVEN an unfold should NOT force dismiss the keyguard
+ when(mActiveUnlockConfig.shouldWakeupForceDismissKeyguard(
+ PowerManager.WAKE_REASON_UNFOLD_DEVICE)).thenReturn(false);
+
+ // WHEN device wakes up from an unfold
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNFOLD_DEVICE);
+ mTestableLooper.processAllMessages();
+
+ // THEN request unlock WITHOUT a keyguard dismissal
+ verify(mTrustManager).reportUserRequestedUnlock(eq(KeyguardUpdateMonitor.getCurrentUser()),
+ eq(false));
+ }
+
private void userDeviceLockDown() {
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId))
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index 3d0d036..456702b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -43,6 +43,7 @@
import com.android.systemui.doze.util.BurnInHelperKt;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
@@ -159,9 +160,12 @@
mAuthRippleController,
mResources,
new KeyguardTransitionInteractor(mTransitionRepository),
- new KeyguardInteractor(new FakeKeyguardRepository(),
+ new KeyguardInteractor(
+ new FakeKeyguardRepository(),
mCommandQueue,
- mFeatureFlags),
+ mFeatureFlags,
+ new FakeKeyguardBouncerRepository()
+ ),
mFeatureFlags
);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
index 472d207..f370ad6 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
@@ -286,4 +286,26 @@
// THEN the lock icon is shown
verify(mLockIconView).setContentDescription(LOCKED_LABEL);
}
+
+ @Test
+ public void lockIconShows_afterUnlockStateChanges() {
+ // GIVEN lock icon controller is initialized and view is attached
+ init(/* useMigrationFlag= */false);
+ captureKeyguardStateCallback();
+ captureKeyguardUpdateMonitorCallback();
+
+ // GIVEN user has unlocked with a biometric auth (ie: face auth)
+ // and biometric running state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
+ mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
+ BiometricSourceType.FACE);
+ reset(mLockIconView);
+
+ // WHEN the unlocked state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(false);
+ mKeyguardStateCallback.onUnlockedChanged();
+
+ // THEN the lock icon is shown
+ verify(mLockIconView).setContentDescription(LOCKED_LABEL);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt
index 4439586..2283746 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt
@@ -18,9 +18,13 @@
import android.app.job.JobParameters
import android.content.Context
+import android.os.PersistableBundle
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapper.DeletionJobService.Companion.USER
+import com.android.systemui.util.mockito.whenever
+import java.util.concurrent.TimeUnit
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -28,18 +32,15 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-import java.util.concurrent.TimeUnit
@SmallTest
@RunWith(AndroidTestingRunner::class)
class DeletionJobServiceTest : SysuiTestCase() {
- @Mock
- private lateinit var context: Context
+ @Mock private lateinit var context: Context
private lateinit var service: AuxiliaryPersistenceWrapper.DeletionJobService
@@ -53,6 +54,10 @@
@Test
fun testOnStartJob() {
+ val bundle = PersistableBundle().also { it.putInt(USER, 0) }
+ val params = mock(JobParameters::class.java)
+ whenever(params.getExtras()).thenReturn(bundle)
+
// false means job is terminated
assertFalse(service.onStartJob(mock(JobParameters::class.java)))
verify(context).deleteFile(AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME)
@@ -67,13 +72,17 @@
@Test
fun testJobHasRightParameters() {
val userId = 10
- `when`(context.userId).thenReturn(userId)
- `when`(context.packageName).thenReturn(mContext.packageName)
+ whenever(context.userId).thenReturn(userId)
+ whenever(context.packageName).thenReturn(mContext.packageName)
- val jobInfo = AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context)
+ val jobInfo =
+ AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context, userId)
assertEquals(
- AuxiliaryPersistenceWrapper.DeletionJobService.DELETE_FILE_JOB_ID + userId, jobInfo.id)
+ AuxiliaryPersistenceWrapper.DeletionJobService.DELETE_FILE_JOB_ID + userId,
+ jobInfo.id
+ )
assertTrue(jobInfo.isPersisted)
+ assertEquals(userId, jobInfo.getExtras().getInt(USER))
assertEquals(TimeUnit.DAYS.toMillis(7), jobInfo.minLatencyMillis)
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 4415033..15a454b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -39,6 +39,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -172,6 +173,7 @@
repository = FakeKeyguardRepository(),
commandQueue = commandQueue,
featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
registry = mock(),
lockPatternUtils = lockPatternUtils,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 8bb6a85..0469e77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -324,29 +324,6 @@
}
@Test
- fun isBouncerShowing() =
- runTest(UnconfinedTestDispatcher()) {
- whenever(keyguardStateController.isBouncerShowing).thenReturn(false)
- var latest: Boolean? = null
- val job = underTest.isBouncerShowing.onEach { latest = it }.launchIn(this)
-
- assertThat(latest).isFalse()
-
- val captor = argumentCaptor<KeyguardStateController.Callback>()
- verify(keyguardStateController).addCallback(captor.capture())
-
- whenever(keyguardStateController.isBouncerShowing).thenReturn(true)
- captor.value.onBouncerShowingChanged()
- assertThat(latest).isTrue()
-
- whenever(keyguardStateController.isBouncerShowing).thenReturn(false)
- captor.value.onBouncerShowingChanged()
- assertThat(latest).isFalse()
-
- job.cancel()
- }
-
- @Test
fun isKeyguardGoingAway() =
runTest(UnconfinedTestDispatcher()) {
whenever(keyguardStateController.isKeyguardGoingAway).thenReturn(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
index 7ded354..18e80ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -130,7 +130,7 @@
givenCanShowAlternateBouncer()
assertTrue(underTest.show())
- assertTrue(bouncerRepository.isAlternateBouncerVisible.value)
+ assertTrue(bouncerRepository.alternateBouncerVisible.value)
}
@Test
@@ -138,7 +138,7 @@
givenCannotShowAlternateBouncer()
assertFalse(underTest.show())
- assertFalse(bouncerRepository.isAlternateBouncerVisible.value)
+ assertFalse(bouncerRepository.alternateBouncerVisible.value)
}
@Test
@@ -146,7 +146,7 @@
bouncerRepository.setAlternateVisible(true)
assertTrue(underTest.hide())
- assertFalse(bouncerRepository.isAlternateBouncerVisible.value)
+ assertFalse(bouncerRepository.alternateBouncerVisible.value)
}
@Test
@@ -154,7 +154,7 @@
bouncerRepository.setAlternateVisible(false)
assertFalse(underTest.hide())
- assertFalse(bouncerRepository.isAlternateBouncerVisible.value)
+ assertFalse(bouncerRepository.alternateBouncerVisible.value)
}
private fun givenCanShowAlternateBouncer() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 7d4861b..153439e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
import com.android.systemui.settings.DisplayTracker
@@ -38,7 +39,6 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@SmallTest
@@ -50,6 +50,7 @@
private lateinit var underTest: KeyguardInteractor
private lateinit var repository: FakeKeyguardRepository
+ private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
@Before
fun setUp() {
@@ -58,7 +59,14 @@
commandQueue = FakeCommandQueue(mock(Context::class.java), mock(DisplayTracker::class.java))
testScope = TestScope()
repository = FakeKeyguardRepository()
- underTest = KeyguardInteractor(repository, commandQueue, featureFlags)
+ bouncerRepository = FakeKeyguardBouncerRepository()
+ underTest =
+ KeyguardInteractor(
+ repository,
+ commandQueue,
+ featureFlags,
+ bouncerRepository,
+ )
}
@Test
@@ -137,7 +145,7 @@
repository.setKeyguardOccluded(true)
assertThat(secureCameraActive()).isTrue()
- repository.setBouncerShowing(true)
+ bouncerRepository.setPrimaryVisible(true)
assertThat(secureCameraActive()).isFalse()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index 240af7b..23e06ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -36,6 +36,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
@@ -298,6 +299,7 @@
repository = FakeKeyguardRepository(),
commandQueue = commandQueue,
featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
registry =
FakeKeyguardQuickAffordanceRegistry(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index ec70857..1b8c627 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -36,6 +36,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
@@ -159,7 +160,8 @@
KeyguardInteractor(
repository = repository,
commandQueue = commandQueue,
- featureFlags = featureFlags
+ featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
registry =
FakeKeyguardQuickAffordanceRegistry(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 46e4679..ae7a928 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -22,7 +22,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Interpolators
import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositoryImpl
@@ -65,6 +67,7 @@
private lateinit var testScope: TestScope
private lateinit var keyguardRepository: FakeKeyguardRepository
+ private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
private lateinit var shadeRepository: ShadeRepository
// Used to issue real transition steps for test input
@@ -81,6 +84,10 @@
private lateinit var fromOccludedTransitionInteractor: FromOccludedTransitionInteractor
private lateinit var fromGoneTransitionInteractor: FromGoneTransitionInteractor
private lateinit var fromAodTransitionInteractor: FromAodTransitionInteractor
+ private lateinit var fromAlternateBouncerTransitionInteractor:
+ FromAlternateBouncerTransitionInteractor
+ private lateinit var fromPrimaryBouncerTransitionInteractor:
+ FromPrimaryBouncerTransitionInteractor
@Before
fun setUp() {
@@ -88,6 +95,7 @@
testScope = TestScope()
keyguardRepository = FakeKeyguardRepository()
+ bouncerRepository = FakeKeyguardBouncerRepository()
shadeRepository = FakeShadeRepository()
/* Used to issue full transition steps, to better simulate a real device */
@@ -98,8 +106,7 @@
fromLockscreenTransitionInteractor =
FromLockscreenTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
shadeRepository = shadeRepository,
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
@@ -109,8 +116,7 @@
fromDreamingTransitionInteractor =
FromDreamingTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -119,8 +125,7 @@
fromAodTransitionInteractor =
FromAodTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -129,8 +134,7 @@
fromGoneTransitionInteractor =
FromGoneTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -139,8 +143,7 @@
fromDozingTransitionInteractor =
FromDozingTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
@@ -149,12 +152,29 @@
fromOccludedTransitionInteractor =
FromOccludedTransitionInteractor(
scope = testScope,
- keyguardInteractor =
- KeyguardInteractor(keyguardRepository, commandQueue, featureFlags),
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
)
fromOccludedTransitionInteractor.start()
+
+ fromAlternateBouncerTransitionInteractor =
+ FromAlternateBouncerTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardTransitionRepository = mockTransitionRepository,
+ keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ )
+ fromAlternateBouncerTransitionInteractor.start()
+
+ fromPrimaryBouncerTransitionInteractor =
+ FromPrimaryBouncerTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(featureFlags),
+ keyguardTransitionRepository = mockTransitionRepository,
+ keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ )
+ fromPrimaryBouncerTransitionInteractor.start()
}
@Test
@@ -256,7 +276,7 @@
}
@Test
- fun `LOCKSCREEN to BOUNCER via bouncer showing call`() =
+ fun `LOCKSCREEN to PRIMARY_BOUNCER via bouncer showing call`() =
testScope.runTest {
// GIVEN a device that has at least woken up
keyguardRepository.setWakefulnessModel(startingToWake())
@@ -278,18 +298,18 @@
)
runCurrent()
- // WHEN the bouncer is set to show
- keyguardRepository.setBouncerShowing(true)
+ // WHEN the primary bouncer is set to show
+ bouncerRepository.setPrimaryVisible(true)
runCurrent()
val info =
withArgCaptor<TransitionInfo> {
verify(mockTransitionRepository).startTransition(capture())
}
- // THEN a transition to BOUNCER should occur
+ // THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.to).isEqualTo(KeyguardState.BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
assertThat(info.animator).isNotNull()
coroutineContext.cancelChildren()
@@ -695,6 +715,297 @@
coroutineContext.cancelChildren()
}
+ @Test
+ fun `ALTERNATE_BOUNCER to PRIMARY_BOUNCER`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to ALTERNATE_BOUNCER
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // WHEN the alternateBouncer stops showing and then the primary bouncer shows
+ bouncerRepository.setPrimaryVisible(true)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to PRIMARY_BOUNCER should occur
+ assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `ALTERNATE_BOUNCER to AOD`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to ALTERNATE_BOUNCER
+ bouncerRepository.setAlternateVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN the primary bouncer isn't showing, aod available and starting to sleep
+ bouncerRepository.setPrimaryVisible(false)
+ keyguardRepository.setAodAvailable(true)
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+
+ // WHEN the alternateBouncer stops showing
+ bouncerRepository.setAlternateVisible(false)
+ advanceUntilIdle()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to AOD should occur
+ assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.AOD)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `ALTERNATE_BOUNCER to DOZING`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to ALTERNATE_BOUNCER
+ bouncerRepository.setAlternateVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN the primary bouncer isn't showing, aod not available and starting to sleep
+ // to sleep
+ bouncerRepository.setPrimaryVisible(false)
+ keyguardRepository.setAodAvailable(false)
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+
+ // WHEN the alternateBouncer stops showing
+ bouncerRepository.setAlternateVisible(false)
+ advanceUntilIdle()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to DOZING should occur
+ assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.DOZING)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `ALTERNATE_BOUNCER to LOCKSCREEN`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to ALTERNATE_BOUNCER
+ bouncerRepository.setAlternateVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN the primary bouncer isn't showing and device not sleeping
+ bouncerRepository.setPrimaryVisible(false)
+ keyguardRepository.setWakefulnessModel(startingToWake())
+
+ // WHEN the alternateBouncer stops showing
+ bouncerRepository.setAlternateVisible(false)
+ advanceUntilIdle()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to LOCKSCREEN should occur
+ assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.ALTERNATE_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `PRIMARY_BOUNCER to AOD`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to PRIMARY_BOUNCER
+ bouncerRepository.setPrimaryVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN aod available and starting to sleep
+ keyguardRepository.setAodAvailable(true)
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+
+ // WHEN the primaryBouncer stops showing
+ bouncerRepository.setPrimaryVisible(false)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to AOD should occur
+ assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.AOD)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `PRIMARY_BOUNCER to DOZING`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to PRIMARY_BOUNCER
+ bouncerRepository.setPrimaryVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN aod not available and starting to sleep to sleep
+ keyguardRepository.setAodAvailable(false)
+ keyguardRepository.setWakefulnessModel(startingToSleep())
+
+ // WHEN the primaryBouncer stops showing
+ bouncerRepository.setPrimaryVisible(false)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to DOZING should occur
+ assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.DOZING)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
+ @Test
+ fun `PRIMARY_BOUNCER to LOCKSCREEN`() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to PRIMARY_BOUNCER
+ bouncerRepository.setPrimaryVisible(true)
+ runner.startTransition(
+ testScope,
+ TransitionInfo(
+ ownerName = "",
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.PRIMARY_BOUNCER,
+ animator =
+ ValueAnimator().apply {
+ duration = 10
+ interpolator = Interpolators.LINEAR
+ },
+ )
+ )
+ runCurrent()
+ reset(mockTransitionRepository)
+
+ // GIVEN device not sleeping
+ keyguardRepository.setWakefulnessModel(startingToWake())
+
+ // WHEN the alternateBouncer stops showing
+ bouncerRepository.setPrimaryVisible(false)
+ runCurrent()
+
+ val info =
+ withArgCaptor<TransitionInfo> {
+ verify(mockTransitionRepository).startTransition(capture())
+ }
+ // THEN a transition to LOCKSCREEN should occur
+ assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
+ assertThat(info.from).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
+ assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(info.animator).isNotNull()
+
+ coroutineContext.cancelChildren()
+ }
+
private fun startingToWake() =
WakefulnessModel(
WakefulnessState.STARTING_TO_WAKE,
@@ -710,4 +1021,13 @@
WakeSleepReason.OTHER,
WakeSleepReason.OTHER
)
+
+ private fun createKeyguardInteractor(featureFlags: FeatureFlags): KeyguardInteractor {
+ return KeyguardInteractor(
+ keyguardRepository,
+ commandQueue,
+ featureFlags,
+ bouncerRepository,
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
index c5e0252..46ed829 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -102,7 +102,7 @@
verify(repository).setPrimaryScrimmed(true)
verify(repository).setPanelExpansion(EXPANSION_VISIBLE)
verify(repository).setPrimaryShowingSoon(true)
- verify(keyguardStateController).notifyBouncerShowing(true)
+ verify(keyguardStateController).notifyPrimaryBouncerShowing(true)
verify(mPrimaryBouncerCallbackInteractor).dispatchStartingToShow()
verify(repository).setPrimaryVisible(true)
verify(repository).setPrimaryShow(any(KeyguardBouncerModel::class.java))
@@ -118,7 +118,7 @@
@Test
fun testShow_keyguardIsDone() {
`when`(bouncerView.delegate?.showNextSecurityScreenOrFinish()).thenReturn(true)
- verify(keyguardStateController, never()).notifyBouncerShowing(true)
+ verify(keyguardStateController, never()).notifyPrimaryBouncerShowing(true)
verify(mPrimaryBouncerCallbackInteractor, never()).dispatchStartingToShow()
}
@@ -126,7 +126,7 @@
fun testHide() {
underTest.hide()
verify(falsingCollector).onBouncerHidden()
- verify(keyguardStateController).notifyBouncerShowing(false)
+ verify(keyguardStateController).notifyPrimaryBouncerShowing(false)
verify(repository).setPrimaryShowingSoon(false)
verify(repository).setPrimaryVisible(false)
verify(repository).setPrimaryHide(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 03a347e..6afeddd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -35,6 +35,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
@@ -136,6 +137,7 @@
repository = repository,
commandQueue = commandQueue,
featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
)
whenever(userTracker.userHandle).thenReturn(mock())
whenever(lockPatternUtils.getStrongAuthForUser(anyInt()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
index 020a866..3fd19ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
@@ -30,12 +30,14 @@
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.nio.file.Files
import java.util.concurrent.Executor
-import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.isNull
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
@@ -61,36 +63,83 @@
UserFileManagerImpl(context, userManager, broadcastDispatcher, backgroundExecutor)
}
- @After
- fun end() {
- val dir = Environment.buildPath(context.filesDir, UserFileManagerImpl.ID)
- dir.deleteRecursively()
- }
-
@Test
fun testGetFile() {
assertThat(userFileManager.getFile(TEST_FILE_NAME, 0).path)
.isEqualTo("${context.filesDir}/$TEST_FILE_NAME")
assertThat(userFileManager.getFile(TEST_FILE_NAME, 11).path)
- .isEqualTo("${context.filesDir}/${UserFileManagerImpl.ID}/11/files/$TEST_FILE_NAME")
+ .isEqualTo("${context.filesDir}/__USER_11_$TEST_FILE_NAME")
}
@Test
fun testGetSharedPreferences() {
+ val primarySharedPref = userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 0)
val secondarySharedPref = userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 11)
- val secondaryUserDir =
- Environment.buildPath(
- context.filesDir,
- UserFileManagerImpl.ID,
- "11",
- UserFileManagerImpl.SHARED_PREFS,
- TEST_FILE_NAME
- )
- assertThat(secondarySharedPref).isNotNull()
- assertThat(secondaryUserDir.exists())
- assertThat(userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 0))
- .isNotEqualTo(secondarySharedPref)
+ assertThat(primarySharedPref).isNotEqualTo(secondarySharedPref)
+
+ // Make sure these are different files
+ primarySharedPref.edit().putString("TEST", "ABC").commit()
+ assertThat(secondarySharedPref.getString("TEST", null)).isNull()
+
+ context.deleteSharedPreferences("TEST")
+ context.deleteSharedPreferences("__USER_11_TEST")
+ }
+
+ @Test
+ fun testMigrateFile() {
+ val userId = 12
+ val fileName = "myFile.txt"
+ val fileContents = "TestingFile"
+ val legacyFile =
+ UserFileManagerImpl.createLegacyFile(
+ context,
+ UserFileManagerImpl.FILES,
+ fileName,
+ userId
+ )!!
+
+ // Write file to legacy area
+ Files.createDirectories(legacyFile.getParentFile().toPath())
+ Files.write(legacyFile.toPath(), fileContents.toByteArray())
+ assertThat(legacyFile.exists()).isTrue()
+
+ // getFile() should migrate the legacy file to the new location
+ val file = userFileManager.getFile(fileName, userId)
+ val newContents = String(Files.readAllBytes(file.toPath()))
+
+ assertThat(newContents).isEqualTo(fileContents)
+ assertThat(legacyFile.exists()).isFalse()
+ assertThat(File(context.filesDir, UserFileManagerImpl.ROOT_DIR).exists()).isFalse()
+ }
+
+ @Test
+ fun testMigrateSharedPrefs() {
+ val userId = 13
+ val fileName = "myFile"
+ val contents = "TestingSharedPrefs"
+ val legacyFile =
+ UserFileManagerImpl.createLegacyFile(
+ context,
+ UserFileManagerImpl.SHARED_PREFS,
+ "$fileName.xml",
+ userId
+ )!!
+
+ // Write a valid shared prefs xml file to legacy area
+ val tmpPrefs = context.getSharedPreferences("tmp", Context.MODE_PRIVATE)
+ tmpPrefs.edit().putString(contents, contents).commit()
+ Files.createDirectories(legacyFile.getParentFile().toPath())
+ val tmpFile =
+ Environment.buildPath(context.dataDir, UserFileManagerImpl.SHARED_PREFS, "tmp.xml")
+ tmpFile.renameTo(legacyFile)
+ assertThat(legacyFile.exists()).isTrue()
+
+ // getSharedpreferences() should migrate the legacy file to the new location
+ val prefs = userFileManager.getSharedPreferences(fileName, Context.MODE_PRIVATE, userId)
+ assertThat(prefs.getString(contents, "")).isEqualTo(contents)
+ assertThat(legacyFile.exists()).isFalse()
+ assertThat(File(context.filesDir, UserFileManagerImpl.ROOT_DIR).exists()).isFalse()
}
@Test
@@ -111,44 +160,14 @@
@Test
fun testClearDeletedUserData() {
- val dir = Environment.buildPath(context.filesDir, UserFileManagerImpl.ID, "11", "files")
- dir.mkdirs()
- val file =
- Environment.buildPath(
- context.filesDir,
- UserFileManagerImpl.ID,
- "11",
- "files",
- TEST_FILE_NAME
- )
- val secondaryUserDir =
- Environment.buildPath(
- context.filesDir,
- UserFileManagerImpl.ID,
- "11",
- )
+ val file = userFileManager.getFile(TEST_FILE_NAME, 11)
file.createNewFile()
- assertThat(secondaryUserDir.exists()).isTrue()
+
assertThat(file.exists()).isTrue()
userFileManager.clearDeletedUserData()
assertThat(backgroundExecutor.runAllReady()).isGreaterThan(0)
- verify(userManager).aliveUsers
- assertThat(secondaryUserDir.exists()).isFalse()
- assertThat(file.exists()).isFalse()
- }
+ verify(userManager, atLeastOnce()).aliveUsers
- @Test
- fun testEnsureParentDirExists() {
- val file =
- Environment.buildPath(
- context.filesDir,
- UserFileManagerImpl.ID,
- "11",
- "files",
- TEST_FILE_NAME
- )
- assertThat(file.parentFile.exists()).isFalse()
- UserFileManagerImpl.ensureParentDirExists(file)
- assertThat(file.parentFile.exists()).isTrue()
+ assertThat(file.exists()).isFalse()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index d01edcc..26eff61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -230,7 +230,7 @@
}
@Test
- fun pluginRemoved_clockChanged() {
+ fun pluginRemoved_clockAndListChanged() {
val plugin1 = FakeClockPlugin()
.addClock("clock_1", "clock 1")
.addClock("clock_2", "clock 2")
@@ -239,20 +239,36 @@
.addClock("clock_3", "clock 3", { mockClock })
.addClock("clock_4", "clock 4")
- registry.applySettings(ClockSettings("clock_3", null))
- pluginListener.onPluginConnected(plugin1, mockContext)
- pluginListener.onPluginConnected(plugin2, mockContext)
var changeCallCount = 0
- registry.registerClockChangeListener { changeCallCount++ }
+ var listChangeCallCount = 0
+ registry.registerClockChangeListener(object : ClockRegistry.ClockChangeListener {
+ override fun onCurrentClockChanged() { changeCallCount++ }
+ override fun onAvailableClocksChanged() { listChangeCallCount++ }
+ })
+
+ registry.applySettings(ClockSettings("clock_3", null))
+ assertEquals(0, changeCallCount)
+ assertEquals(0, listChangeCallCount)
+
+ pluginListener.onPluginConnected(plugin1, mockContext)
+ assertEquals(0, changeCallCount)
+ assertEquals(1, listChangeCallCount)
+
+ pluginListener.onPluginConnected(plugin2, mockContext)
+ assertEquals(1, changeCallCount)
+ assertEquals(2, listChangeCallCount)
pluginListener.onPluginDisconnected(plugin1)
- assertEquals(0, changeCallCount)
+ assertEquals(1, changeCallCount)
+ assertEquals(3, listChangeCallCount)
pluginListener.onPluginDisconnected(plugin2)
- assertEquals(1, changeCallCount)
+ assertEquals(2, changeCallCount)
+ assertEquals(4, listChangeCallCount)
}
+
@Test
fun jsonDeserialization_gotExpectedObject() {
val expected = ClockSettings("ID", null).apply { _applied_timestamp = 500 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 5832569..4d9db8c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -518,7 +518,7 @@
val childHunView = createHunViewMock(
isShadeOpen = true,
fullyVisible = false,
- headerVisibleAmount = 1f,
+ headerVisibleAmount = 1f
)
val algorithmState = StackScrollAlgorithm.StackScrollAlgorithmState()
algorithmState.visibleChildren.add(childHunView)
@@ -526,6 +526,7 @@
// When: updateChildZValue() is called for the top HUN
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
+ /* childrenOnTop= */ 0.0f,
/* StackScrollAlgorithmState= */ algorithmState,
/* ambientState= */ ambientState,
/* shouldElevateHun= */ true
@@ -545,7 +546,7 @@
val childHunView = createHunViewMock(
isShadeOpen = true,
fullyVisible = false,
- headerVisibleAmount = 1f,
+ headerVisibleAmount = 1f
)
// Use half of the HUN's height as overlap
childHunView.viewState.yTranslation = (childHunView.viewState.height + 1 shr 1).toFloat()
@@ -555,6 +556,7 @@
// When: updateChildZValue() is called for the top HUN
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
+ /* childrenOnTop= */ 0.0f,
/* StackScrollAlgorithmState= */ algorithmState,
/* ambientState= */ ambientState,
/* shouldElevateHun= */ true
@@ -578,7 +580,7 @@
val childHunView = createHunViewMock(
isShadeOpen = true,
fullyVisible = true,
- headerVisibleAmount = 1f,
+ headerVisibleAmount = 1f
)
// HUN doesn't overlap with QQS Panel
childHunView.viewState.yTranslation = ambientState.topPadding +
@@ -589,6 +591,7 @@
// When: updateChildZValue() is called for the top HUN
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
+ /* childrenOnTop= */ 0.0f,
/* StackScrollAlgorithmState= */ algorithmState,
/* ambientState= */ ambientState,
/* shouldElevateHun= */ true
@@ -608,7 +611,7 @@
val childHunView = createHunViewMock(
isShadeOpen = false,
fullyVisible = false,
- headerVisibleAmount = 0f,
+ headerVisibleAmount = 0f
)
childHunView.viewState.yTranslation = 0f
// Shade is closed, thus childHunView's headerVisibleAmount is 0
@@ -619,6 +622,7 @@
// When: updateChildZValue() is called for the top HUN
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
+ /* childrenOnTop= */ 0.0f,
/* StackScrollAlgorithmState= */ algorithmState,
/* ambientState= */ ambientState,
/* shouldElevateHun= */ true
@@ -638,7 +642,7 @@
val childHunView = createHunViewMock(
isShadeOpen = false,
fullyVisible = false,
- headerVisibleAmount = 0.5f,
+ headerVisibleAmount = 0.5f
)
childHunView.viewState.yTranslation = 0f
// Shade is being opened, thus childHunView's headerVisibleAmount is between 0 and 1
@@ -650,6 +654,7 @@
// When: updateChildZValue() is called for the top HUN
stackScrollAlgorithm.updateChildZValue(
/* i= */ 0,
+ /* childrenOnTop= */ 0.0f,
/* StackScrollAlgorithmState= */ algorithmState,
/* ambientState= */ ambientState,
/* shouldElevateHun= */ true
@@ -664,7 +669,7 @@
private fun createHunViewMock(
isShadeOpen: Boolean,
fullyVisible: Boolean,
- headerVisibleAmount: Float,
+ headerVisibleAmount: Float
) =
mock<ExpandableNotificationRow>().apply {
val childViewStateMock = createHunChildViewState(isShadeOpen, fullyVisible)
@@ -675,10 +680,7 @@
}
- private fun createHunChildViewState(
- isShadeOpen: Boolean,
- fullyVisible: Boolean,
- ) =
+ private fun createHunChildViewState(isShadeOpen: Boolean, fullyVisible: Boolean) =
ExpandableViewState().apply {
// Mock the HUN's height with ambientState.topPadding +
// ambientState.stackTranslation
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java
index a986777..c669c6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java
@@ -53,7 +53,7 @@
}
@Override
- public boolean isBouncerShowing() {
+ public boolean isPrimaryBouncerShowing() {
return false;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt
index 5a6bb30..ab888f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt
@@ -18,9 +18,9 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.google.common.truth.Truth.assertThat
@@ -42,7 +42,7 @@
private lateinit var underTest: AirplaneModeViewModelImpl
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: TableLogBuffer
private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
private lateinit var connectivityRepository: FakeConnectivityRepository
private lateinit var interactor: AirplaneModeInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
index 521c67f..0145103 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
@@ -25,7 +25,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -53,7 +53,7 @@
private lateinit var mockitoSession: MockitoSession
private lateinit var carrierConfigCoreStartable: CarrierConfigCoreStartable
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: MobileInputLogger
@Mock private lateinit var carrierConfigManager: CarrierConfigManager
@Mock private lateinit var dumpManager: DumpManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 4da2104..17502f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -33,8 +33,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.validMobileEvent
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
import com.android.systemui.util.mockito.any
@@ -81,7 +81,7 @@
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var subscriptionManager: SubscriptionManager
@Mock private lateinit var telephonyManager: TelephonyManager
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: MobileInputLogger
@Mock private lateinit var summaryLogger: TableLogBuffer
@Mock private lateinit var demoModeController: DemoModeController
@Mock private lateinit var dumpManager: DumpManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index a294088a..b2577e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -65,8 +65,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import com.android.systemui.util.mockito.any
@@ -94,7 +94,7 @@
private lateinit var connectionsRepo: FakeMobileConnectionsRepository
@Mock private lateinit var telephonyManager: TelephonyManager
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: MobileInputLogger
@Mock private lateinit var tableLogger: TableLogBuffer
private val scope = CoroutineScope(IMMEDIATE)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 8090205..09b7a66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -42,8 +42,8 @@
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName
+import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.util.mockito.any
@@ -86,7 +86,7 @@
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var subscriptionManager: SubscriptionManager
@Mock private lateinit var telephonyManager: TelephonyManager
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: MobileInputLogger
@Mock private lateinit var summaryLogger: TableLogBuffer
@Mock private lateinit var logBufferFactory: TableLogBufferFactory
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index bbca001..c51dbf1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -85,7 +85,6 @@
MobileIconsInteractorImpl(
connectionsRepository,
carrierConfigTracker,
- logger = mock(),
tableLogger = mock(),
connectivityRepository,
userSetupRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt
new file mode 100644
index 0000000..86529dc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.shared
+
+import android.net.Network
+import android.net.NetworkCapabilities
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import org.junit.Test
+import org.mockito.Mockito
+import org.mockito.Mockito.mock
+
+@SmallTest
+class MobileInputLoggerTest : SysuiTestCase() {
+ private val buffer =
+ LogBufferFactory(DumpManager(), mock(LogcatEchoTracker::class.java)).create("buffer", 10)
+ private val logger = MobileInputLogger(buffer)
+
+ @Test
+ fun testLogNetworkCapsChange_bufferHasInfo() {
+ logger.logOnCapabilitiesChanged(NET_1, NET_1_CAPS, isDefaultNetworkCallback = true)
+
+ val stringWriter = StringWriter()
+ buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+ val actualString = stringWriter.toString()
+
+ val expectedNetId = NET_1_ID.toString()
+ val expectedCaps = NET_1_CAPS.toString()
+
+ assertThat(actualString).contains("true")
+ assertThat(actualString).contains(expectedNetId)
+ assertThat(actualString).contains(expectedCaps)
+ }
+
+ @Test
+ fun testLogOnLost_bufferHasNetIdOfLostNetwork() {
+ logger.logOnLost(NET_1)
+
+ val stringWriter = StringWriter()
+ buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+ val actualString = stringWriter.toString()
+
+ val expectedNetId = NET_1_ID.toString()
+
+ assertThat(actualString).contains(expectedNetId)
+ }
+
+ companion object {
+ private const val NET_1_ID = 100
+ private val NET_1 =
+ com.android.systemui.util.mockito.mock<Network>().also {
+ Mockito.`when`(it.getNetId()).thenReturn(NET_1_ID)
+ }
+ private val NET_1_CAPS =
+ NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
+ .build()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index d9268a2..4628f84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -26,7 +26,6 @@
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
@@ -51,7 +50,6 @@
private lateinit var airplaneModeInteractor: AirplaneModeInteractor
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
- @Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var constants: ConnectivityConstants
private val testDispatcher = UnconfinedTestDispatcher()
@@ -77,7 +75,6 @@
subscriptionIdsFlow,
interactor,
airplaneModeInteractor,
- logger,
constants,
testScope.backgroundScope,
statusBarPipelineFlags,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
deleted file mode 100644
index 3dccbbf..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.shared
-
-import android.net.Network
-import android.net.NetworkCapabilities
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.log.LogBufferFactory
-import com.android.systemui.plugins.log.LogcatEchoTracker
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
-import com.google.common.truth.Truth.assertThat
-import java.io.PrintWriter
-import java.io.StringWriter
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.runBlocking
-import org.junit.Test
-import org.mockito.Mockito
-import org.mockito.Mockito.mock
-
-@SmallTest
-class ConnectivityPipelineLoggerTest : SysuiTestCase() {
- private val buffer = LogBufferFactory(DumpManager(), mock(LogcatEchoTracker::class.java))
- .create("buffer", 10)
- private val logger = ConnectivityPipelineLogger(buffer)
-
- @Test
- fun testLogNetworkCapsChange_bufferHasInfo() {
- logger.logOnCapabilitiesChanged(NET_1, NET_1_CAPS, isDefaultNetworkCallback = true)
-
- val stringWriter = StringWriter()
- buffer.dump(PrintWriter(stringWriter), tailLength = 0)
- val actualString = stringWriter.toString()
-
- val expectedNetId = NET_1_ID.toString()
- val expectedCaps = NET_1_CAPS.toString()
-
- assertThat(actualString).contains("true")
- assertThat(actualString).contains(expectedNetId)
- assertThat(actualString).contains(expectedCaps)
- }
-
- @Test
- fun testLogOnLost_bufferHasNetIdOfLostNetwork() {
- logger.logOnLost(NET_1)
-
- val stringWriter = StringWriter()
- buffer.dump(PrintWriter(stringWriter), tailLength = 0)
- val actualString = stringWriter.toString()
-
- val expectedNetId = NET_1_ID.toString()
-
- assertThat(actualString).contains(expectedNetId)
- }
-
- @Test
- fun logOutputChange_printsValuesAndNulls() = runBlocking(IMMEDIATE) {
- val flow: Flow<Int?> = flowOf(1, null, 3)
-
- val job = flow
- .logOutputChange(logger, "testInts")
- .launchIn(this)
-
- val stringWriter = StringWriter()
- buffer.dump(PrintWriter(stringWriter), tailLength = 0)
- val actualString = stringWriter.toString()
-
- assertThat(actualString).contains("1")
- assertThat(actualString).contains("null")
- assertThat(actualString).contains("3")
-
- job.cancel()
- }
-
- @Test
- fun logInputChange_unit_printsInputName() = runBlocking(IMMEDIATE) {
- val flow: Flow<Unit> = flowOf(Unit, Unit)
-
- val job = flow
- .logInputChange(logger, "testInputs")
- .launchIn(this)
-
- val stringWriter = StringWriter()
- buffer.dump(PrintWriter(stringWriter), tailLength = 0)
- val actualString = stringWriter.toString()
-
- assertThat(actualString).contains("testInputs")
-
- job.cancel()
- }
-
- @Test
- fun logInputChange_any_printsValuesAndNulls() = runBlocking(IMMEDIATE) {
- val flow: Flow<Any?> = flowOf(null, 2, "threeString")
-
- val job = flow
- .logInputChange(logger, "testInputs")
- .launchIn(this)
-
- val stringWriter = StringWriter()
- buffer.dump(PrintWriter(stringWriter), tailLength = 0)
- val actualString = stringWriter.toString()
-
- assertThat(actualString).contains("null")
- assertThat(actualString).contains("2")
- assertThat(actualString).contains("threeString")
-
- job.cancel()
- }
-
- companion object {
- private const val NET_1_ID = 100
- private val NET_1 = com.android.systemui.util.mockito.mock<Network>().also {
- Mockito.`when`(it.getNetId()).thenReturn(NET_1_ID)
- }
- private val NET_1_CAPS = NetworkCapabilities.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
- .build()
- private val IMMEDIATE = Dispatchers.Main.immediate
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
index 6dbee2f..496f090 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
@@ -19,7 +19,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityInputLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.DEFAULT_HIDDEN_ICONS_RESOURCE
@@ -52,7 +52,7 @@
@Mock private lateinit var connectivitySlots: ConnectivitySlots
@Mock private lateinit var dumpManager: DumpManager
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: ConnectivityInputLogger
private lateinit var scope: CoroutineScope
@Mock private lateinit var tunerService: TunerService
@@ -61,14 +61,15 @@
MockitoAnnotations.initMocks(this)
scope = CoroutineScope(IMMEDIATE)
- underTest = ConnectivityRepositoryImpl(
- connectivitySlots,
- context,
- dumpManager,
- logger,
- scope,
- tunerService,
- )
+ underTest =
+ ConnectivityRepositoryImpl(
+ connectivitySlots,
+ context,
+ dumpManager,
+ logger,
+ scope,
+ tunerService,
+ )
}
@After
@@ -77,199 +78,179 @@
}
@Test
- fun forceHiddenSlots_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
- context.getOrCreateTestableResources().addOverride(
- DEFAULT_HIDDEN_ICONS_RESOURCE,
- arrayOf(SLOT_WIFI, SLOT_ETHERNET)
- )
- // Re-create our [ConnectivityRepositoryImpl], since it fetches
- // config_statusBarIconsToExclude when it's first constructed
- underTest = ConnectivityRepositoryImpl(
- connectivitySlots,
- context,
- dumpManager,
- logger,
- scope,
- tunerService,
- )
+ fun forceHiddenSlots_initiallyGetsDefault() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
+ context
+ .getOrCreateTestableResources()
+ .addOverride(DEFAULT_HIDDEN_ICONS_RESOURCE, arrayOf(SLOT_WIFI, SLOT_ETHERNET))
+ // Re-create our [ConnectivityRepositoryImpl], since it fetches
+ // config_statusBarIconsToExclude when it's first constructed
+ underTest =
+ ConnectivityRepositoryImpl(
+ connectivitySlots,
+ context,
+ dumpManager,
+ logger,
+ scope,
+ tunerService,
+ )
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
+ assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_slotNamesAdded_flowHasSlots() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
+ fun forceHiddenSlots_slotNamesAdded_flowHasSlots() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
- assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+ assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_wrongKey_doesNotUpdate() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
+ fun forceHiddenSlots_wrongKey_doesNotUpdate() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
- // WHEN onTuningChanged with the wrong key
- getTunable().onTuningChanged("wrongKey", SLOT_WIFI)
- yield()
+ // WHEN onTuningChanged with the wrong key
+ getTunable().onTuningChanged("wrongKey", SLOT_WIFI)
+ yield()
- // THEN we didn't update our value and still have the old one
- assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+ // THEN we didn't update our value and still have the old one
+ assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_slotNamesAddedThenNull_flowHasDefault() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
- context.getOrCreateTestableResources().addOverride(
- DEFAULT_HIDDEN_ICONS_RESOURCE,
- arrayOf(SLOT_WIFI, SLOT_ETHERNET)
- )
- // Re-create our [ConnectivityRepositoryImpl], since it fetches
- // config_statusBarIconsToExclude when it's first constructed
- underTest = ConnectivityRepositoryImpl(
- connectivitySlots,
- context,
- dumpManager,
- logger,
- scope,
- tunerService,
- )
+ fun forceHiddenSlots_slotNamesAddedThenNull_flowHasDefault() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
+ context
+ .getOrCreateTestableResources()
+ .addOverride(DEFAULT_HIDDEN_ICONS_RESOURCE, arrayOf(SLOT_WIFI, SLOT_ETHERNET))
+ // Re-create our [ConnectivityRepositoryImpl], since it fetches
+ // config_statusBarIconsToExclude when it's first constructed
+ underTest =
+ ConnectivityRepositoryImpl(
+ connectivitySlots,
+ context,
+ dumpManager,
+ logger,
+ scope,
+ tunerService,
+ )
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- // First, update the slots
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
- assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+ // First, update the slots
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+ assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
- // WHEN we update to a null value
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, null)
- yield()
+ // WHEN we update to a null value
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, null)
+ yield()
- // THEN we go back to our default value
- assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
+ // THEN we go back to our default value
+ assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_someInvalidSlotNames_flowHasValidSlotsOnly() = runBlocking(IMMEDIATE) {
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ fun forceHiddenSlots_someInvalidSlotNames_flowHasValidSlotsOnly() =
+ runBlocking(IMMEDIATE) {
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- whenever(connectivitySlots.getSlotFromName(SLOT_WIFI))
- .thenReturn(ConnectivitySlot.WIFI)
- whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
+ whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(ConnectivitySlot.WIFI)
+ whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_MOBILE")
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_MOBILE")
- assertThat(latest).containsExactly(ConnectivitySlot.WIFI)
+ assertThat(latest).containsExactly(ConnectivitySlot.WIFI)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_someEmptySlotNames_flowHasValidSlotsOnly() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
+ fun forceHiddenSlots_someEmptySlotNames_flowHasValidSlotsOnly() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- // WHEN there's empty and blank slot names
- getTunable().onTuningChanged(
- HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE, ,,$SLOT_WIFI"
- )
+ // WHEN there's empty and blank slot names
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE, ,,$SLOT_WIFI")
- // THEN we skip that slot but still process the other ones
- assertThat(latest).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.MOBILE)
+ // THEN we skip that slot but still process the other ones
+ assertThat(latest).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.MOBILE)
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_allInvalidOrEmptySlotNames_flowHasEmpty() = runBlocking(IMMEDIATE) {
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest
- .forceHiddenSlots
- .onEach { latest = it }
- .launchIn(this)
+ fun forceHiddenSlots_allInvalidOrEmptySlotNames_flowHasEmpty() =
+ runBlocking(IMMEDIATE) {
+ var latest: Set<ConnectivitySlot>? = null
+ val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
- whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(null)
- whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET)).thenReturn(null)
- whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
+ whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(null)
+ whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET)).thenReturn(null)
+ whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
- getTunable().onTuningChanged(
- HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE,,$SLOT_WIFI,$SLOT_ETHERNET,,,"
- )
+ getTunable()
+ .onTuningChanged(
+ HIDDEN_ICONS_TUNABLE_KEY,
+ "$SLOT_MOBILE,,$SLOT_WIFI,$SLOT_ETHERNET,,,"
+ )
- assertThat(latest).isEmpty()
+ assertThat(latest).isEmpty()
- job.cancel()
- }
+ job.cancel()
+ }
@Test
- fun forceHiddenSlots_newSubscriberGetsCurrentValue() = runBlocking(IMMEDIATE) {
- setUpEthernetWifiMobileSlotNames()
+ fun forceHiddenSlots_newSubscriberGetsCurrentValue() =
+ runBlocking(IMMEDIATE) {
+ setUpEthernetWifiMobileSlotNames()
- var latest1: Set<ConnectivitySlot>? = null
- val job1 = underTest
- .forceHiddenSlots
- .onEach { latest1 = it }
- .launchIn(this)
+ var latest1: Set<ConnectivitySlot>? = null
+ val job1 = underTest.forceHiddenSlots.onEach { latest1 = it }.launchIn(this)
- getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_ETHERNET")
+ getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_ETHERNET")
- assertThat(latest1).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
+ assertThat(latest1).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
- // WHEN we add a second subscriber after having already emitted a value
- var latest2: Set<ConnectivitySlot>? = null
- val job2 = underTest
- .forceHiddenSlots
- .onEach { latest2 = it }
- .launchIn(this)
+ // WHEN we add a second subscriber after having already emitted a value
+ var latest2: Set<ConnectivitySlot>? = null
+ val job2 = underTest.forceHiddenSlots.onEach { latest2 = it }.launchIn(this)
- // THEN the second subscribe receives the already-emitted value
- assertThat(latest2).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
+ // THEN the second subscribe receives the already-emitted value
+ assertThat(latest2).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
- job1.cancel()
- job2.cancel()
- }
+ job1.cancel()
+ job2.cancel()
+ }
private fun getTunable(): TunerService.Tunable {
val callbackCaptor = argumentCaptor<TunerService.Tunable>()
@@ -280,10 +261,8 @@
private fun setUpEthernetWifiMobileSlotNames() {
whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET))
.thenReturn(ConnectivitySlot.ETHERNET)
- whenever(connectivitySlots.getSlotFromName(SLOT_WIFI))
- .thenReturn(ConnectivitySlot.WIFI)
- whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE))
- .thenReturn(ConnectivitySlot.MOBILE)
+ whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(ConnectivitySlot.WIFI)
+ whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(ConnectivitySlot.MOBILE)
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
index 1085c2b..25678b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
@@ -23,11 +23,11 @@
import com.android.systemui.demomode.DemoMode
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
+import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.kotlinArgumentCaptor
import com.android.systemui.util.mockito.whenever
@@ -47,6 +47,7 @@
import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@SmallTest
class WifiRepositorySwitcherTest : SysuiTestCase() {
private lateinit var underTest: WifiRepositorySwitcher
@@ -54,7 +55,7 @@
private lateinit var demoImpl: DemoWifiRepository
@Mock private lateinit var demoModeController: DemoModeController
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: WifiInputLogger
@Mock private lateinit var tableLogger: TableLogBuffer
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var wifiManager: WifiManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index db791bb..c7b31bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -34,9 +34,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
+import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -72,7 +72,7 @@
private lateinit var underTest: WifiRepositoryImpl
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
- @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var logger: WifiInputLogger
@Mock private lateinit var tableLogger: TableLogBuffer
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var wifiManager: WifiManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
index 60f564e..64810d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
@@ -36,7 +36,6 @@
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
@@ -63,7 +62,6 @@
private lateinit var testableLooper: TestableLooper
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
- @Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var tableLogBuffer: TableLogBuffer
@Mock private lateinit var connectivityConstants: ConnectivityConstants
@Mock private lateinit var wifiConstants: WifiConstants
@@ -92,7 +90,7 @@
airplaneModeRepository,
connectivityRepository,
),
- logger,
+ tableLogBuffer,
scope,
)
viewModel =
@@ -100,7 +98,6 @@
airplaneModeViewModel,
connectivityConstants,
context,
- logger,
tableLogBuffer,
interactor,
scope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
index 648d7a5..12b1664 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
@@ -33,7 +33,6 @@
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
@@ -68,7 +67,6 @@
private lateinit var underTest: WifiViewModel
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
- @Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var tableLogBuffer: TableLogBuffer
@Mock private lateinit var connectivityConstants: ConnectivityConstants
@Mock private lateinit var wifiConstants: WifiConstants
@@ -94,7 +92,7 @@
airplaneModeRepository,
connectivityRepository,
),
- logger,
+ tableLogBuffer,
scope,
)
}
@@ -125,7 +123,6 @@
airplaneModeViewModel,
connectivityConstants,
context,
- logger,
tableLogBuffer,
interactor,
scope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index 45ebb39..7a62cb8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -25,7 +25,6 @@
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
@@ -59,7 +58,6 @@
private lateinit var underTest: WifiViewModel
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
- @Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var tableLogBuffer: TableLogBuffer
@Mock private lateinit var connectivityConstants: ConnectivityConstants
@Mock private lateinit var wifiConstants: WifiConstants
@@ -85,7 +83,7 @@
airplaneModeRepository,
connectivityRepository,
),
- logger,
+ tableLogBuffer,
scope,
)
@@ -478,7 +476,6 @@
airplaneModeViewModel,
connectivityConstants,
context,
- logger,
tableLogBuffer,
interactor,
scope,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index 3d75967..a87e61a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.shade.NotificationPanelViewController
@@ -112,7 +113,8 @@
KeyguardInteractor(
repository = keyguardRepository,
commandQueue = commandQueue,
- featureFlags = featureFlags
+ featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
)
// Needs to be run on the main thread
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index 22d05bf..f0a53ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -38,6 +38,7 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
@@ -145,6 +146,7 @@
repository = keyguardRepository,
commandQueue = commandQueue,
featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
manager = manager,
headlessSystemUserMode = headlessSystemUserMode,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
index 2f05e65..bc0881c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
@@ -31,6 +31,7 @@
import com.android.systemui.common.shared.model.Text
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
@@ -251,6 +252,7 @@
repository = keyguardRepository,
commandQueue = commandQueue,
featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
featureFlags = featureFlags,
manager = manager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index 9268904..c8b0496 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.common.shared.model.Text
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
@@ -152,7 +153,8 @@
KeyguardInteractor(
repository = keyguardRepository,
commandQueue = commandQueue,
- featureFlags = featureFlags
+ featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
),
featureFlags = featureFlags,
manager = manager,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt
index d0383e9..3374219 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt
@@ -57,10 +57,10 @@
override val bouncerPromptReason = 0
override val bouncerErrorMessage: CharSequence? = null
private val _isAlternateBouncerVisible = MutableStateFlow(false)
- override val isAlternateBouncerVisible = _isAlternateBouncerVisible.asStateFlow()
+ override val alternateBouncerVisible = _isAlternateBouncerVisible.asStateFlow()
override var lastAlternateBouncerVisibleTime: Long = 0L
private val _isAlternateBouncerUIAvailable = MutableStateFlow<Boolean>(false)
- override val isAlternateBouncerUIAvailable = _isAlternateBouncerUIAvailable.asStateFlow()
+ override val alternateBouncerUIAvailable = _isAlternateBouncerUIAvailable.asStateFlow()
override fun setPrimaryScrimmed(isScrimmed: Boolean) {
_primaryBouncerScrimmed.value = isScrimmed
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 065fe89..1a371c7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -84,9 +84,6 @@
private val _isUdfpsSupported = MutableStateFlow(false)
- private val _isBouncerShowing = MutableStateFlow(false)
- override val isBouncerShowing: Flow<Boolean> = _isBouncerShowing
-
private val _isKeyguardGoingAway = MutableStateFlow(false)
override val isKeyguardGoingAway: Flow<Boolean> = _isKeyguardGoingAway
@@ -153,10 +150,6 @@
_wakefulnessModel.value = model
}
- fun setBouncerShowing(isShowing: Boolean) {
- _isBouncerShowing.value = isShowing
- }
-
fun setBiometricUnlockState(state: BiometricUnlockModel) {
_biometricUnlockState.tryEmit(state)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
index 95b62a1..bdf1aff 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
@@ -49,7 +49,7 @@
}
@Override
- public boolean isBouncerShowing() {
+ public boolean isPrimaryBouncerShowing() {
return false;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 72c5598..328b971 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3819,20 +3819,30 @@
+ "proxy-ed");
}
- mProxyManager.registerProxy(client, displayId, mContext,
- sIdCounter++, mMainHandler, mSecurityPolicy, this, getTraceManager(),
- mWindowManagerService, mA11yWindowManager);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mProxyManager.registerProxy(client, displayId, mContext,
+ sIdCounter++, mMainHandler, mSecurityPolicy, this, getTraceManager(),
+ mWindowManagerService, mA11yWindowManager);
- synchronized (mLock) {
- notifyClearAccessibilityCacheLocked();
+ synchronized (mLock) {
+ notifyClearAccessibilityCacheLocked();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
return true;
}
@Override
- public boolean unregisterProxyForDisplay(int displayId) throws RemoteException {
+ public boolean unregisterProxyForDisplay(int displayId) {
mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
- return mProxyManager.unregisterProxy(displayId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mProxyManager.unregisterProxy(displayId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
boolean isDisplayProxyed(int displayId) {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index dc475f6..3a7aa85 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -158,19 +158,19 @@
/**
* The user that the backup is activated by default for.
*
- * If there is a {@link UserManager#getMainUser()}, this will be that user. If not, it will be
- * {@link UserHandle#USER_SYSTEM}.
+ * <p>If there is a {@link UserManager#getMainUser()}, this will be that user. If not, it will
+ * be {@link UserHandle#USER_SYSTEM}.
+ *
+ * <p>Note: on the first ever boot of a new device, this might change once the first user is
+ * unlocked. See {@link #updateDefaultBackupUserIdIfNeeded()}.
*
* @see #isBackupActivatedForUser(int)
*/
- @UserIdInt private final int mDefaultBackupUserId;
+ @UserIdInt private int mDefaultBackupUserId;
+
+ private boolean mHasFirstUserUnlockedSinceBoot = false;
public BackupManagerService(Context context) {
- this(context, new SparseArray<>());
- }
-
- @VisibleForTesting
- BackupManagerService(Context context, SparseArray<UserBackupManagerService> userServices) {
mContext = context;
mGlobalDisable = isBackupDisabled();
HandlerThread handlerThread =
@@ -178,7 +178,7 @@
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
mUserManager = UserManager.get(context);
- mUserServices = userServices;
+ mUserServices = new SparseArray<>();
Set<ComponentName> transportWhitelist =
SystemConfig.getInstance().getBackupTransportWhitelist();
mTransportWhitelist = (transportWhitelist == null) ? emptySet() : transportWhitelist;
@@ -186,6 +186,9 @@
mUserRemovedReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
UserHandle mainUser = getUserManager().getMainUser();
mDefaultBackupUserId = mainUser == null ? UserHandle.USER_SYSTEM : mainUser.getIdentifier();
+ if (DEBUG) {
+ Slog.d(TAG, "Default backup user id = " + mDefaultBackupUserId);
+ }
}
// TODO: Remove this when we implement DI by injecting in the construtor.
@@ -361,17 +364,6 @@
}
/**
- * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked.
- * Starts the backup service for this user if backup is active for this user. Offloads work onto
- * the handler thread {@link #mHandlerThread} to keep unlock time low since backup is not
- * essential for device functioning.
- */
- @VisibleForTesting
- void onUnlockUser(int userId) {
- postToHandler(() -> startServiceForUser(userId));
- }
-
- /**
* Starts the backup service for user {@code userId} by creating a new instance of {@link
* UserBackupManagerService} and registering it with this service.
*/
@@ -1687,7 +1679,15 @@
@Override
public void onUserUnlocking(@NonNull TargetUser user) {
- sInstance.onUnlockUser(user.getUserIdentifier());
+ // Starts the backup service for this user if backup is active for this user. Offloads
+ // work onto the handler thread {@link #mHandlerThread} to keep unlock time low since
+ // backup is not essential for device functioning.
+ sInstance.postToHandler(
+ () -> {
+ sInstance.updateDefaultBackupUserIdIfNeeded();
+ sInstance.startServiceForUser(user.getUserIdentifier());
+ sInstance.mHasFirstUserUnlockedSinceBoot = true;
+ });
}
@Override
@@ -1700,4 +1700,42 @@
publishBinderService(name, service);
}
}
+
+ /**
+ * On the first ever boot of a new device, the 'main' user might not exist for a short period of
+ * time and be created after {@link BackupManagerService} is created. In this case the {@link
+ * #mDefaultBackupUserId} will be the system user initially, but we need to change it to the
+ * newly created {@link UserManager#getMainUser()} later.
+ *
+ * <p>{@link Lifecycle#onUserUnlocking(SystemService.TargetUser)} (for any user) is the earliest
+ * point where we know that a main user (if there is going to be one) is created.
+ */
+ private void updateDefaultBackupUserIdIfNeeded() {
+ // The default user can only change before any user unlocks since boot, and it will only
+ // change from the system user to a non-system user.
+ if (mHasFirstUserUnlockedSinceBoot || mDefaultBackupUserId != UserHandle.USER_SYSTEM) {
+ return;
+ }
+
+ UserHandle mainUser = getUserManager().getMainUser();
+ if (mainUser == null) {
+ return;
+ }
+
+ if (mDefaultBackupUserId != mainUser.getIdentifier()) {
+ int oldDefaultBackupUserId = mDefaultBackupUserId;
+ mDefaultBackupUserId = mainUser.getIdentifier();
+ // We don't expect the service to be started for the old default user but we attempt to
+ // stop its service to be safe.
+ if (!isBackupActivatedForUser(oldDefaultBackupUserId)) {
+ stopServiceForUser(oldDefaultBackupUserId);
+ }
+ Slog.i(
+ TAG,
+ "Default backup user changed from "
+ + oldDefaultBackupUserId
+ + " to "
+ + mDefaultBackupUserId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index a66e598..57a0713 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -416,6 +416,11 @@
LinkCapacityEstimate.INVALID, LinkCapacityEstimate.INVALID)));
private List<List<LinkCapacityEstimate>> mLinkCapacityEstimateLists;
+ private int[] mECBMReason;
+ private boolean[] mECBMStarted;
+ private int[] mSCBMReason;
+ private boolean[] mSCBMStarted;
+
/**
* Per-phone map of precise data connection state. The key of the map is the pair of transport
* type and APN setting. This is the cache to prevent redundant callbacks to the listeners.
@@ -556,7 +561,8 @@
return events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)
|| events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
|| events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED)
- || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED);
+ || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED);
}
private static final int MSG_USER_SWITCHED = 1;
@@ -707,7 +713,10 @@
mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones);
mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones);
mAllowedNetworkTypeValue = copyOf(mAllowedNetworkTypeValue, mNumPhones);
-
+ mECBMReason = copyOf(mECBMReason, mNumPhones);
+ mECBMStarted = copyOf(mECBMStarted, mNumPhones);
+ mSCBMReason = copyOf(mSCBMReason, mNumPhones);
+ mSCBMStarted = copyOf(mSCBMStarted, mNumPhones);
// ds -> ss switch.
if (mNumPhones < oldNumPhones) {
cutListToSize(mCellInfo, mNumPhones);
@@ -762,6 +771,10 @@
mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID));
+ mECBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
+ mECBMStarted[i] = false;
+ mSCBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
+ mSCBMStarted[i] = false;
}
}
}
@@ -831,6 +844,10 @@
mLinkCapacityEstimateLists = new ArrayList<>();
mCarrierPrivilegeStates = new ArrayList<>();
mCarrierServiceStates = new ArrayList<>();
+ mECBMReason = new int[numPhones];
+ mECBMStarted = new boolean[numPhones];
+ mSCBMReason = new int[numPhones];
+ mSCBMStarted = new boolean[numPhones];
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
@@ -870,6 +887,10 @@
mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0]));
mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID));
+ mECBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
+ mECBMStarted[i] = false;
+ mSCBMReason[i] = TelephonyManager.STOP_REASON_UNKNOWN;
+ mSCBMStarted[i] = false;
}
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -1441,6 +1462,31 @@
}
}
}
+ if (events.contains(TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)) {
+ try {
+ boolean ecbmStarted = mECBMStarted[r.phoneId];
+ if (ecbmStarted) {
+ r.callback.onCallBackModeStarted(
+ TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL);
+ } else {
+ r.callback.onCallBackModeStopped(
+ TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL,
+ mECBMReason[r.phoneId]);
+ }
+
+ boolean scbmStarted = mSCBMStarted[r.phoneId];
+ if (scbmStarted) {
+ r.callback.onCallBackModeStarted(
+ TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS);
+ } else {
+ r.callback.onCallBackModeStopped(
+ TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS,
+ mSCBMReason[r.phoneId]);
+ }
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
}
@@ -3258,6 +3304,72 @@
}
}
+ @Override
+ public void notifyCallbackModeStarted(int phoneId, int subId, int type) {
+ if (!checkNotifyPermission("notifyCallbackModeStarted()")) {
+ return;
+ }
+ if (VDBG) {
+ log("notifyCallbackModeStarted: phoneId=" + phoneId + ", subId=" + subId
+ + ", type=" + type);
+ }
+ synchronized (mRecords) {
+ if (validatePhoneId(phoneId)) {
+ if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL) {
+ mECBMStarted[phoneId] = true;
+ } else if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS) {
+ mSCBMStarted[phoneId] = true;
+ }
+ }
+ for (Record r : mRecords) {
+ // Send to all listeners regardless of subscription
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)) {
+ try {
+ r.callback.onCallBackModeStarted(type);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+
+ @Override
+ public void notifyCallbackModeStopped(int phoneId, int subId, int type, int reason) {
+ if (!checkNotifyPermission("notifyCallbackModeStopped()")) {
+ return;
+ }
+ if (VDBG) {
+ log("notifyCallbackModeStopped: phoneId=" + phoneId + ", subId=" + subId
+ + ", type=" + type + ", reason=" + reason);
+ }
+ synchronized (mRecords) {
+ if (validatePhoneId(phoneId)) {
+ if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL) {
+ mECBMStarted[phoneId] = false;
+ mECBMReason[phoneId] = reason;
+ } else if (type == TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS) {
+ mSCBMStarted[phoneId] = false;
+ mSCBMReason[phoneId] = reason;
+ }
+ }
+ for (Record r : mRecords) {
+ // Send to all listeners regardless of subscription
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)) {
+ try {
+ r.callback.onCallBackModeStopped(type, reason);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+
@NeverCompile // Avoid size overhead of debugging code.
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -3307,6 +3419,11 @@
pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]);
pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs.get(i));
pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i));
+ pw.println("mECBMReason=" + mECBMReason[i]);
+ pw.println("mECBMStarted=" + mECBMStarted[i]);
+ pw.println("mSCBMReason=" + mSCBMReason[i]);
+ pw.println("mSCBMStarted=" + mSCBMStarted[i]);
+
// We need to obfuscate package names, and primitive arrays' native toString is ugly
Pair<List<String>, int[]> carrierPrivilegeState = mCarrierPrivilegeStates.get(i);
pw.println(
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index f5ca8aa..82e6e30 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1882,6 +1882,10 @@
? BrightnessEvent.FLAG_USER_SET : 0));
Slog.i(mTag, newEvent.toString(/* includeTime= */ false));
+ // Log all events which are not temporary
+ if (newEvent.getReason().getReason() != BrightnessReason.REASON_TEMPORARY) {
+ logBrightnessEvent(newEvent, unthrottledBrightnessState);
+ }
if (userSetBrightnessChanged) {
logManualBrightnessEvent(newEvent);
}
@@ -2976,6 +2980,154 @@
}
}
+ // Return bucket index of range_[left]_[right] where
+ // left <= nits < right
+ private int nitsToRangeIndex(float nits) {
+ float[] boundaries = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80,
+ 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1200,
+ 1400, 1600, 1800, 2000, 2250, 2500, 2750, 3000};
+ int[] rangeIndex = {
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_UNKNOWN,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_0_1,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1_2,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2_3,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_3_4,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_4_5,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_5_6,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_6_7,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_7_8,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_8_9,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_9_10,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_10_20,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_20_30,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_30_40,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_40_50,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_50_60,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_60_70,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_70_80,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_80_90,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_90_100,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_100_200,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_200_300,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_300_400,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_400_500,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_500_600,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_600_700,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_700_800,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_800_900,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_900_1000,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1000_1200,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1200_1400,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1400_1600,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1600_1800,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1800_2000,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2000_2250,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2250_2500,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2500_2750,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2750_3000,
+ };
+ for (int i = 0; i < boundaries.length; i++) {
+ if (nits < boundaries[i]) {
+ return rangeIndex[i];
+ }
+ }
+ return FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_3000_INF;
+ }
+
+ private int convertBrightnessReasonToStatsEnum(int brightnessReason) {
+ switch(brightnessReason) {
+ case BrightnessReason.REASON_UNKNOWN:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_UNKNOWN;
+ case BrightnessReason.REASON_MANUAL:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_MANUAL;
+ case BrightnessReason.REASON_DOZE:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_DOZE;
+ case BrightnessReason.REASON_DOZE_DEFAULT:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_DOZE_DEFAULT;
+ case BrightnessReason.REASON_AUTOMATIC:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_AUTOMATIC;
+ case BrightnessReason.REASON_SCREEN_OFF:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_SCREEN_OFF;
+ case BrightnessReason.REASON_OVERRIDE:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_OVERRIDE;
+ case BrightnessReason.REASON_TEMPORARY:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_TEMPORARY;
+ case BrightnessReason.REASON_BOOST:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_BOOST;
+ case BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_SCREEN_OFF_BRIGHTNESS_SENSOR;
+ case BrightnessReason.REASON_FOLLOWER:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_FOLLOWER;
+ }
+ return FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_UNKNOWN;
+ }
+
+ private int convertHbmModeToStatsEnum(int mode) {
+ switch(mode) {
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_OFF;
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_SUNLIGHT;
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_HDR;
+ }
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_OFF;
+ }
+
+ // unmodifiedBrightness: the brightness value that has not been
+ // modified by any modifiers(dimming/throttling/low-power-mode)
+ private void logBrightnessEvent(BrightnessEvent event, float unmodifiedBrightness) {
+ int modifier = event.getReason().getModifier();
+ // It's easier to check if the brightness is at maximum level using the brightness
+ // value untouched by any modifiers
+ boolean brightnessIsMax = unmodifiedBrightness == event.getHbmMax();
+ float brightnessInNits = convertToNits(event.getBrightness());
+ float lowPowerModeFactor = event.getPowerFactor();
+ int rbcStrength = event.getRbcStrength();
+ float hbmMaxNits = convertToNits(event.getHbmMax());
+ float thermalCapNits = convertToNits(event.getThermalMax());
+
+ if (mLogicalDisplay.getPrimaryDisplayDeviceLocked() != null
+ && mLogicalDisplay.getPrimaryDisplayDeviceLocked()
+ .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL) {
+ FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2,
+ event.getPhysicalDisplayId().hashCode(),
+ brightnessInNits,
+ convertToNits(unmodifiedBrightness),
+ nitsToRangeIndex(brightnessInNits),
+ brightnessIsMax,
+ (event.getFlags() & BrightnessEvent.FLAG_USER_SET) > 0,
+ convertBrightnessReasonToStatsEnum(event.getReason().getReason()),
+ convertHbmModeToStatsEnum(event.getHbmMode()),
+ (modifier & BrightnessReason.MODIFIER_LOW_POWER) > 0,
+ (modifier & BrightnessReason.MODIFIER_THROTTLED) > 0,
+ event.isRbcEnabled(),
+ event.getLux(),
+ event.wasShortTermModelActive(),
+ lowPowerModeFactor,
+ rbcStrength,
+ hbmMaxNits,
+ thermalCapNits,
+ event.isAutomaticBrightnessEnabled());
+ }
+ }
+
private void logManualBrightnessEvent(BrightnessEvent event) {
float appliedLowPowerMode = event.isLowPowerModeSet() ? event.getPowerFactor() : -1f;
int appliedRbcStrength = event.isRbcEnabled() ? event.getRbcStrength() : -1;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 5667ddf..39bc09e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -1595,6 +1595,10 @@
? BrightnessEvent.FLAG_USER_SET : 0));
Slog.i(mTag, newEvent.toString(/* includeTime= */ false));
+ // Log all events which are not temporary
+ if (newEvent.getReason().getReason() != BrightnessReason.REASON_TEMPORARY) {
+ logBrightnessEvent(newEvent, unthrottledBrightnessState);
+ }
if (userSetBrightnessChanged) {
logManualBrightnessEvent(newEvent);
}
@@ -2512,6 +2516,154 @@
}
}
+ // Return bucket index of range_[left]_[right] where
+ // left <= nits < right
+ private int nitsToRangeIndex(float nits) {
+ float[] boundaries = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80,
+ 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1200,
+ 1400, 1600, 1800, 2000, 2250, 2500, 2750, 3000};
+ int[] rangeIndex = {
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_UNKNOWN,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_0_1,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1_2,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2_3,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_3_4,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_4_5,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_5_6,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_6_7,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_7_8,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_8_9,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_9_10,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_10_20,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_20_30,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_30_40,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_40_50,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_50_60,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_60_70,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_70_80,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_80_90,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_90_100,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_100_200,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_200_300,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_300_400,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_400_500,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_500_600,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_600_700,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_700_800,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_800_900,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_900_1000,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1000_1200,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1200_1400,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1400_1600,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1600_1800,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_1800_2000,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2000_2250,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2250_2500,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2500_2750,
+ FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_2750_3000,
+ };
+ for (int i = 0; i < boundaries.length; i++) {
+ if (nits < boundaries[i]) {
+ return rangeIndex[i];
+ }
+ }
+ return FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__BUCKET_INDEX__RANGE_3000_INF;
+ }
+
+ private int convertBrightnessReasonToStatsEnum(int brightnessReason) {
+ switch(brightnessReason) {
+ case BrightnessReason.REASON_UNKNOWN:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_UNKNOWN;
+ case BrightnessReason.REASON_MANUAL:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_MANUAL;
+ case BrightnessReason.REASON_DOZE:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_DOZE;
+ case BrightnessReason.REASON_DOZE_DEFAULT:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_DOZE_DEFAULT;
+ case BrightnessReason.REASON_AUTOMATIC:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_AUTOMATIC;
+ case BrightnessReason.REASON_SCREEN_OFF:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_SCREEN_OFF;
+ case BrightnessReason.REASON_OVERRIDE:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_OVERRIDE;
+ case BrightnessReason.REASON_TEMPORARY:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_TEMPORARY;
+ case BrightnessReason.REASON_BOOST:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_BOOST;
+ case BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_SCREEN_OFF_BRIGHTNESS_SENSOR;
+ case BrightnessReason.REASON_FOLLOWER:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_FOLLOWER;
+ }
+ return FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2__REASON__REASON_UNKNOWN;
+ }
+
+ private int convertHbmModeToStatsEnum(int mode) {
+ switch(mode) {
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_OFF;
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_SUNLIGHT;
+ case BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR:
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_HDR;
+ }
+ return FrameworkStatsLog
+ .SCREEN_BRIGHTNESS_CHANGED_V2__HBM_MODE__HIGH_BRIGHTNESS_MODE_OFF;
+ }
+
+ // unmodifiedBrightness: the brightness value that has not been
+ // modified by any modifiers(dimming/throttling/low-power-mode)
+ private void logBrightnessEvent(BrightnessEvent event, float unmodifiedBrightness) {
+ int modifier = event.getReason().getModifier();
+ // It's easier to check if the brightness is at maximum level using the brightness
+ // value untouched by any modifiers
+ boolean brightnessIsMax = unmodifiedBrightness == event.getHbmMax();
+ float brightnessInNits = convertToNits(event.getBrightness());
+ float lowPowerModeFactor = event.getPowerFactor();
+ int rbcStrength = event.getRbcStrength();
+ float hbmMaxNits = convertToNits(event.getHbmMax());
+ float thermalCapNits = convertToNits(event.getThermalMax());
+
+ if (mLogicalDisplay.getPrimaryDisplayDeviceLocked() != null
+ && mLogicalDisplay.getPrimaryDisplayDeviceLocked()
+ .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL) {
+ FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED_V2,
+ event.getPhysicalDisplayId().hashCode(),
+ brightnessInNits,
+ convertToNits(unmodifiedBrightness),
+ nitsToRangeIndex(brightnessInNits),
+ brightnessIsMax,
+ (event.getFlags() & BrightnessEvent.FLAG_USER_SET) > 0,
+ convertBrightnessReasonToStatsEnum(event.getReason().getReason()),
+ convertHbmModeToStatsEnum(event.getHbmMode()),
+ (modifier & BrightnessReason.MODIFIER_LOW_POWER) > 0,
+ (modifier & BrightnessReason.MODIFIER_THROTTLED) > 0,
+ event.isRbcEnabled(),
+ event.getLux(),
+ event.wasShortTermModelActive(),
+ lowPowerModeFactor,
+ rbcStrength,
+ hbmMaxNits,
+ thermalCapNits,
+ event.isAutomaticBrightnessEnabled());
+ }
+ }
+
private final class DisplayControllerHandler extends Handler {
DisplayControllerHandler(Looper looper) {
super(looper, null, true /*async*/);
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 1823a39..c1171fa 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -18,7 +18,6 @@
import static android.os.PowerExemptionManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
-import static android.safetylabel.SafetyLabelConstants.PERMISSION_RATIONALE_ENABLED;
import static android.safetylabel.SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
@@ -392,8 +391,7 @@
/** Returns whether the Safety Label Change notification, a privacy feature, is enabled. */
public static boolean isPrivacySafetyLabelChangeNotificationsEnabled() {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, false) && DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_PRIVACY, PERMISSION_RATIONALE_ENABLED, false);
+ SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, false);
}
@NonNull
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 25f9ccd..fb6ae8b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -66,6 +66,8 @@
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -124,6 +126,7 @@
import android.os.RemoteException;
import android.os.RevocableFileDescriptor;
import android.os.SELinux;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.incremental.IStorageHealthListener;
@@ -146,6 +149,7 @@
import android.util.EventLog;
import android.util.ExceptionUtils;
import android.util.IntArray;
+import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
import android.util.SparseArray;
@@ -154,6 +158,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.IPlatformCompat;
import com.android.internal.content.InstallLocationUtils;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.messages.nano.SystemMessageProto;
@@ -297,8 +302,18 @@
private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000;
/**
+ * If an app being installed targets {@link Build.VERSION_CODES#S API 31} and above, the app
+ * can be installed without user action.
+ * See {@link PackageInstaller.SessionParams#setRequireUserAction} for other conditions required
+ * to be satisfied for a silent install.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long SILENT_INSTALL_ALLOWED = 265131695L;
+
+ /**
* The default value of {@link #mValidatedTargetSdk} is {@link Integer#MAX_VALUE}. If {@link
- * #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#R} before getting the
+ * #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#S} before getting the
* target sdk version from a validated apk in {@link #validateApkInstallLocked()}, the compared
* result will not trigger any user action in
* {@link #checkUserActionRequirement(PackageInstallerSession, IntentSender)}.
@@ -2353,13 +2368,7 @@
}
if (!session.isApexSession() && userActionRequirement == USER_ACTION_PENDING_APK_PARSING) {
- final int validatedTargetSdk;
- synchronized (session.mLock) {
- validatedTargetSdk = session.mValidatedTargetSdk;
- }
-
- if (validatedTargetSdk != INVALID_TARGET_SDK_VERSION
- && validatedTargetSdk < Build.VERSION_CODES.R) {
+ if (!isTargetSdkConditionSatisfied(session)) {
session.sendPendingUserActionIntent(target);
return true;
}
@@ -2380,6 +2389,39 @@
return false;
}
+ /**
+ * Checks if the app being installed has a targetSdk more than the minimum required for a
+ * silent install. See {@link SessionParams#setRequireUserAction(int)} for details about the
+ * targetSdk requirement.
+ * @param session Current install session
+ * @return true if the targetSdk of the app being installed is more than the minimum required,
+ * resulting in a silent install, false otherwise.
+ */
+ private static boolean isTargetSdkConditionSatisfied(PackageInstallerSession session) {
+ final int validatedTargetSdk;
+ final String packageName;
+ synchronized (session.mLock) {
+ validatedTargetSdk = session.mValidatedTargetSdk;
+ packageName = session.mPackageName;
+ }
+
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName;
+ appInfo.targetSdkVersion = validatedTargetSdk;
+
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ try {
+ // Using manually constructed AppInfo to check if a change is enabled may not work
+ // in the future.
+ return validatedTargetSdk != INVALID_TARGET_SDK_VERSION
+ && platformCompat.isChangeEnabled(SILENT_INSTALL_ALLOWED, appInfo);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
+ return false;
+ }
+ }
+
private static @UserActionReason int userActionRequirementToReason(
@UserActionRequirement int requirement) {
switch (requirement) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 89a9eb0..78761bd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -3305,7 +3305,7 @@
if (Objects.equals(packageName, PLATFORM_PACKAGE_NAME)) {
return true;
}
- if (!packageSetting.isPrivileged()) {
+ if (!(packageSetting.isSystem() && packageSetting.isPrivileged())) {
return true;
}
if (!mPrivilegedPermissionAllowlistSourcePackageNames
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 8ceac79..de7dc3b 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -1394,6 +1394,22 @@
return false
}
+ private fun addAllowlistedRestrictedPermissionsUnchecked(
+ androidPackage: AndroidPackage,
+ appId: Int,
+ permissionNames: List<String>,
+ userId: Int
+ ) {
+ val newPermissionNames = getAllowlistedRestrictedPermissionsUnchecked(appId,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER, userId
+ )?.let {
+ IndexedSet(permissionNames).apply { this += it }.toList()
+ } ?: permissionNames
+
+ setAllowlistedRestrictedPermissionsUnchecked(androidPackage, appId, newPermissionNames,
+ PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER, userId)
+ }
+
override fun removeAllowlistedRestrictedPermission(
packageName: String,
permissionName: String,
@@ -1445,7 +1461,7 @@
private fun setAllowlistedRestrictedPermissions(
packageName: String,
- allowlistedPermissions: List<String>,
+ permissionNames: List<String>,
allowlistedFlags: Int,
userId: Int,
isAddingPermission: Boolean
@@ -1480,7 +1496,7 @@
}
setAllowlistedRestrictedPermissionsUnchecked(
- androidPackage, packageState.appId, allowlistedPermissions, allowlistedFlags, userId
+ androidPackage, packageState.appId, permissionNames, allowlistedFlags, userId
)
return true
@@ -1493,7 +1509,7 @@
private fun setAllowlistedRestrictedPermissionsUnchecked(
androidPackage: AndroidPackage,
appId: Int,
- allowlistedPermissions: List<String>,
+ permissionNames: List<String>,
allowlistedFlags: Int,
userId: Int
) {
@@ -1522,7 +1538,7 @@
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM -> {
mask = mask or PermissionFlags.SYSTEM_EXEMPT
newFlags =
- if (allowlistedPermissions.contains(requestedPermission)) {
+ if (permissionNames.contains(requestedPermission)) {
newFlags or PermissionFlags.SYSTEM_EXEMPT
} else {
newFlags andInv PermissionFlags.SYSTEM_EXEMPT
@@ -1531,7 +1547,7 @@
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE -> {
mask = mask or PermissionFlags.UPGRADE_EXEMPT
newFlags =
- if (allowlistedPermissions.contains(requestedPermission)) {
+ if (permissionNames.contains(requestedPermission)) {
newFlags or PermissionFlags.UPGRADE_EXEMPT
} else {
newFlags andInv PermissionFlags.UPGRADE_EXEMPT
@@ -1540,7 +1556,7 @@
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER -> {
mask = mask or PermissionFlags.INSTALLER_EXEMPT
newFlags =
- if (allowlistedPermissions.contains(requestedPermission)) {
+ if (permissionNames.contains(requestedPermission)) {
newFlags or PermissionFlags.INSTALLER_EXEMPT
} else {
newFlags andInv PermissionFlags.INSTALLER_EXEMPT
@@ -1856,10 +1872,15 @@
@Suppress("NAME_SHADOWING")
userIds.forEach { userId ->
service.onPackageInstalled(androidPackage.packageName, userId)
+ }
+
+ @Suppress("NAME_SHADOWING")
+ userIds.forEach { userId ->
// TODO: Remove when this callback receives packageState directly.
val packageState =
packageManagerInternal.getPackageStateInternal(androidPackage.packageName)!!
- // TODO: Add allowlisting
+ addAllowlistedRestrictedPermissionsUnchecked(androidPackage, packageState.appId,
+ params.allowlistedRestrictedPermissions, userId)
setRequestedPermissionStates(packageState, userId, params.permissionStates)
}
}
diff --git a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
index 59551a3..5a7b37a 100644
--- a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
@@ -962,7 +962,7 @@
if (packageState.packageName == PLATFORM_PACKAGE_NAME) {
return true
}
- if (!packageState.isPrivileged) {
+ if (!(packageState.isSystem && packageState.isPrivileged)) {
return true
}
if (permission.packageName !in newState.systemState.privilegedPermissionAllowlistPackages) {
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index e2f56ba..94ee0a8 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -1584,11 +1584,7 @@
@Test
public void testConstructor_withNullContext_throws() throws Exception {
expectThrows(
- NullPointerException.class,
- () ->
- new BackupManagerService(
- /* context */ null,
- new SparseArray<>()));
+ NullPointerException.class, () -> new BackupManagerService(/* context */ null));
}
/** Test that the constructor does not create {@link UserBackupManagerService} instances. */
@@ -1616,18 +1612,6 @@
verify(lifecycle).publishService(Context.BACKUP_SERVICE, backupManagerService);
}
- /** testOnUnlockUser_forwards */
- @Test
- public void testOnUnlockUser_forwards() {
- BackupManagerService backupManagerService = mock(BackupManagerService.class);
- BackupManagerService.Lifecycle lifecycle =
- new BackupManagerService.Lifecycle(mContext, backupManagerService);
-
- lifecycle.onUserUnlocking(new TargetUser(new UserInfo(UserHandle.USER_SYSTEM, null, 0)));
-
- verify(backupManagerService).onUnlockUser(UserHandle.USER_SYSTEM);
- }
-
/** testOnStopUser_forwards */
@Test
public void testOnStopUser_forwards() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java
index cd9d8a9..b203cf6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -37,7 +37,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-
import android.Manifest;
import android.annotation.UserIdInt;
import android.app.backup.BackupManager;
@@ -54,13 +53,13 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
-import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.server.SystemService;
import com.android.server.backup.utils.RandomAccessFileUtils;
import org.junit.After;
@@ -104,8 +103,8 @@
private FileDescriptor mFileDescriptorStub = new FileDescriptor();
private BackupManagerServiceTestable mService;
+ private BackupManagerService.Lifecycle mServiceLifecycle;
private static File sTestDir;
- private SparseArray<UserBackupManagerService> mUserServices;
private MockitoSession mSession;
@Before
@@ -125,8 +124,6 @@
mUserId = UserHandle.USER_SYSTEM;
- mUserServices = new SparseArray<>();
-
when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);
when(mUserManagerMock.getUserInfo(NON_SYSTEM_USER)).thenReturn(mUserInfoMock);
// Null main user means there is no main user on the device.
@@ -142,8 +139,6 @@
when(mContextMock.getSystemService(Context.JOB_SCHEDULER_SERVICE))
.thenReturn(mock(JobScheduler.class));
- mService = new BackupManagerServiceTestable(mContextMock, mUserServices);
- simulateUserUnlocked(UserHandle.USER_SYSTEM);
}
@After
@@ -154,21 +149,20 @@
@Test
public void onUnlockUser_startsUserService() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
ConditionVariable unlocked = new ConditionVariable(false);
- mService.onUnlockUser(NON_SYSTEM_USER);
- mService.getBackupHandler().post(unlocked::open);
- unlocked.block();
+ simulateUserUnlocked(NON_SYSTEM_USER);
assertNotNull(mService.getUserService(NON_SYSTEM_USER));
}
@Test
public void startServiceForUser_backupDisabledGlobally_doesNotStartUserService() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sBackupDisabled = true;
- BackupManagerServiceTestable service =
- new BackupManagerServiceTestable(mContextMock, new SparseArray<>());
+ BackupManagerServiceTestable service = new BackupManagerServiceTestable(mContextMock);
service.startServiceForUser(UserHandle.USER_SYSTEM);
@@ -177,6 +171,7 @@
@Test
public void startServiceForUser_backupNotActiveForUser_doesNotStartUserService() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
mService.startServiceForUser(UserHandle.USER_SYSTEM);
@@ -186,7 +181,8 @@
@Test
public void startServiceForUser_backupEnabledGloballyAndActiveForUser_startsUserService() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
+
mService.startServiceForUser(NON_SYSTEM_USER);
assertNotNull(mService.getUserService(NON_SYSTEM_USER));
@@ -194,9 +190,9 @@
@Test
public void isBackupServiceActive_backupDisabledGlobally_returnFalse() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sBackupDisabled = true;
- BackupManagerService service =
- new BackupManagerServiceTestable(mContextMock, mUserServices);
+ BackupManagerService service = new BackupManagerServiceTestable(mContextMock);
service.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
assertFalse(service.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -204,6 +200,7 @@
@Test
public void isBackupServiceActive_systemUser_isDefault_deactivated_returnsFalse() {
+ createBackupManagerServiceAndUnlockSystemUser();
// If there's no 'main' user on the device, the default user is the system user.
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
@@ -212,20 +209,23 @@
@Test
public void isBackupServiceActive_systemUser_isNotDefault_returnsFalse() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ createBackupManagerServiceAndUnlockSystemUser();
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
assertFalse(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
}
@Test
public void isBackupServiceActive_systemUser_isDefault_returnsTrue() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
// If there's no 'main' user on the device, the default user is the system user.
assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
}
@Test
public void isBackupServiceActive_nonSystemUser_isDefault_systemUserDeactivated_returnsFalse() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
@@ -233,7 +233,7 @@
@Test
public void isBackupServiceActive_nonSystemUser_isDefault_deactivated_returnsFalse() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
@@ -241,19 +241,24 @@
@Test
public void isBackupServiceActive_nonSystemUser_isDefault_returnsTrue() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ createBackupManagerServiceAndUnlockSystemUser();
+
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
assertTrue(mService.isBackupServiceActive(NON_SYSTEM_USER));
}
@Test
public void isBackupServiceActive_nonSystemUser_isNotDefault_notActivated_returnsFalse() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
// By default non-system non-default users are not activated.
assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
}
@Test
public void isBackupServiceActive_nonSystemUser_isNotDefault_activated_returnsTrue() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
assertTrue(mService.isBackupServiceActive(NON_SYSTEM_USER));
@@ -261,6 +266,7 @@
@Test
public void setBackupServiceActive_forSystemUserAndCallerSystemUid_createsService() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID;
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -270,6 +276,7 @@
@Test
public void setBackupServiceActive_forSystemUserAndCallerRootUid_createsService() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sCallingUid = Process.ROOT_UID;
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -279,6 +286,7 @@
@Test
public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
try {
@@ -290,6 +298,7 @@
@Test
public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_createsService() {
+ createBackupManagerServiceAndUnlockSystemUser();
simulateUserUnlocked(NON_SYSTEM_USER);
when(mUserInfoMock.isManagedProfile()).thenReturn(true);
BackupManagerServiceTestable.sCallingUid = Process.SYSTEM_UID;
@@ -301,6 +310,7 @@
@Test
public void setBackupServiceActive_forManagedProfileAndCallerRootUid_createsService() {
+ createBackupManagerServiceAndUnlockSystemUser();
simulateUserUnlocked(NON_SYSTEM_USER);
when(mUserInfoMock.isManagedProfile()).thenReturn(true);
BackupManagerServiceTestable.sCallingUid = Process.ROOT_UID;
@@ -312,6 +322,7 @@
@Test
public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() {
+ createBackupManagerServiceAndUnlockSystemUser();
when(mUserInfoMock.isManagedProfile()).thenReturn(true);
BackupManagerServiceTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
@@ -324,6 +335,7 @@
@Test
public void setBackupServiceActive_forNonSystemUserAndCallerWithoutBackupPermission_throws() {
+ createBackupManagerServiceAndUnlockSystemUser();
doThrow(new SecurityException())
.when(mContextMock)
.enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString());
@@ -337,6 +349,7 @@
@Test
public void setBackupServiceActive_forNonSystemUserAndCallerWithoutUserPermission_throws() {
+ createBackupManagerServiceAndUnlockSystemUser();
doThrow(new SecurityException())
.when(mContextMock)
.enforceCallingOrSelfPermission(
@@ -351,9 +364,9 @@
@Test
public void setBackupServiceActive_backupDisabledGlobally_ignored() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sBackupDisabled = true;
- BackupManagerServiceTestable service =
- new BackupManagerServiceTestable(mContextMock, mUserServices);
+ BackupManagerServiceTestable service = new BackupManagerServiceTestable(mContextMock);
service.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -362,6 +375,7 @@
@Test
public void setBackupServiceActive_alreadyActive_ignored() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
assertTrue(mService.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -371,6 +385,7 @@
@Test
public void setBackupServiceActive_systemUser_makeActive_deletesSuppressFile() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -380,6 +395,7 @@
@Test
public void setBackupServiceActive_systemUser_makeNonActive_createsSuppressFile() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
assertTrue(getFakeSuppressFileForUser(UserHandle.USER_SYSTEM).exists());
@@ -387,6 +403,7 @@
@Test
public void setBackupServiceActive_systemUser_makeNonActive_stopsUserService() {
+ createBackupManagerServiceAndUnlockSystemUser();
assertTrue(mService.isUserReadyForBackup(UserHandle.USER_SYSTEM));
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
@@ -396,7 +413,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isDefault_makeActive_createsService() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
simulateUserUnlocked(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
@@ -407,7 +424,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isDefault_makeActive_deletesSuppressFile() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
simulateUserUnlocked(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
@@ -418,7 +435,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isDefault_makeNonActive_createsSuppressFile() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
assertTrue(getFakeSuppressFileForUser(NON_SYSTEM_USER).exists());
@@ -426,7 +443,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isDefault_makeNonActive_stopsUserService() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
simulateUserUnlocked(NON_SYSTEM_USER);
assertTrue(mService.isUserReadyForBackup(NON_SYSTEM_USER));
@@ -437,6 +454,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isNotDefault_makeActive_createsService() {
+ createBackupManagerServiceAndUnlockSystemUser();
simulateUserUnlocked(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
@@ -446,6 +464,8 @@
@Test
public void setBackupServiceActive_nonSystemUser_isNotDefault_makeActive_createActivatedFile() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
assertTrue(getFakeActivatedFileForUser(NON_SYSTEM_USER).exists());
@@ -453,6 +473,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isNotDefault_makeNonActive_stopsUserService() {
+ createBackupManagerServiceAndUnlockSystemUser();
simulateUserUnlocked(NON_SYSTEM_USER);
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
@@ -463,6 +484,7 @@
@Test
public void setBackupServiceActive_nonSystemUser_isNotDefault_makeActive_deleteActivatedFile() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
@@ -472,6 +494,7 @@
@Test
public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() {
+ createBackupManagerServiceAndUnlockSystemUser();
int otherUser = NON_SYSTEM_USER + 1;
mService.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -482,6 +505,8 @@
@Test
public void setBackupServiceActive_forNonSystemUser_remembersActivated() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
assertTrue(RandomAccessFileUtils.readBoolean(
@@ -490,6 +515,8 @@
@Test
public void setBackupServiceActiveFalse_forNonSystemUser_remembersActivated() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
assertFalse(RandomAccessFileUtils.readBoolean(
@@ -498,6 +525,8 @@
@Test
public void setBackupServiceActiveTwice_forNonSystemUser_remembersLastActivated() {
+ createBackupManagerServiceAndUnlockSystemUser();
+
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
mService.setBackupServiceActive(NON_SYSTEM_USER, false);
@@ -508,7 +537,7 @@
@Test
public void selectBackupTransportAsyncForUser_beforeUserUnlocked_notifiesBackupNotAllowed()
throws Exception {
- mUserServices.clear();
+ mService = new BackupManagerServiceTestable(mContextMock);
CompletableFuture<Integer> future = new CompletableFuture<>();
ISelectBackupTransportCallback listener =
new ISelectBackupTransportCallback.Stub() {
@@ -531,6 +560,8 @@
@Test
public void selectBackupTransportAsyncForUser_beforeUserUnlockedWithNullListener_doesNotThrow()
throws Exception {
+ createBackupManagerServiceAndUnlockSystemUser();
+
mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
// No crash.
@@ -539,6 +570,8 @@
@Test
public void selectBackupTransportAsyncForUser_beforeUserUnlockedListenerThrowing_doesNotThrow()
throws Exception {
+ createBackupManagerServiceAndUnlockSystemUser();
+
ISelectBackupTransportCallback.Stub listener =
new ISelectBackupTransportCallback.Stub() {
@Override
@@ -558,6 +591,7 @@
@Test
public void dump_callerDoesNotHaveDumpPermission_ignored() {
+ createBackupManagerServiceAndUnlockSystemUser();
when(mContextMock.checkCallingOrSelfPermission(
Manifest.permission.DUMP)).thenReturn(
PackageManager.PERMISSION_DENIED);
@@ -570,6 +604,7 @@
@Test
public void dump_callerDoesNotHavePackageUsageStatsPermission_ignored() {
+ createBackupManagerServiceAndUnlockSystemUser();
when(mContextMock.checkCallingOrSelfPermission(
Manifest.permission.PACKAGE_USAGE_STATS)).thenReturn(
PackageManager.PERMISSION_DENIED);
@@ -586,6 +621,7 @@
*/
@Test
public void testDump_systemUserFirst() {
+ createBackupManagerServiceAndUnlockSystemUser();
mService.setBackupServiceActive(NON_SYSTEM_USER, true);
simulateUserUnlocked(NON_SYSTEM_USER);
String[] args = new String[0];
@@ -602,6 +638,7 @@
@Test
public void testGetUserForAncestralSerialNumber_forSystemUser() {
+ createBackupManagerServiceAndUnlockSystemUser();
simulateUserUnlocked(NON_SYSTEM_USER);
when(mUserManagerMock.getProfileIds(UserHandle.getCallingUserId(), false))
.thenReturn(new int[]{UserHandle.USER_SYSTEM, NON_SYSTEM_USER});
@@ -614,10 +651,10 @@
@Test
public void testGetUserForAncestralSerialNumber_forNonSystemUser() {
- setMockMainUserAndStartNewBackupManagerService(NON_SYSTEM_USER);
+ setMockMainUserAndCreateBackupManagerService(NON_SYSTEM_USER);
simulateUserUnlocked(NON_SYSTEM_USER);
when(mUserManagerMock.getProfileIds(UserHandle.getCallingUserId(), false))
- .thenReturn(new int[]{UserHandle.USER_SYSTEM, NON_SYSTEM_USER});
+ .thenReturn(new int[] {UserHandle.USER_SYSTEM, NON_SYSTEM_USER});
when(mNonSystemUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L);
UserHandle user = mService.getUserForAncestralSerialNumber(11L);
@@ -627,9 +664,9 @@
@Test
public void testGetUserForAncestralSerialNumber_whenDisabled() {
+ createBackupManagerServiceAndUnlockSystemUser();
BackupManagerServiceTestable.sBackupDisabled = true;
- BackupManagerService backupManagerService =
- new BackupManagerServiceTestable(mContextMock, mUserServices);
+ BackupManagerService backupManagerService = new BackupManagerServiceTestable(mContextMock);
when(mSystemUserBackupManagerService.getAncestralSerialNumber()).thenReturn(11L);
UserHandle user = backupManagerService.getUserForAncestralSerialNumber(11L);
@@ -637,18 +674,68 @@
assertThat(user).isNull();
}
+ @Test
+ public void onUserUnlocking_mainUserChanged_firstUnlockAfterReboot_updatesDefaultUser() {
+ // Create BMS *before* setting a main user to simulate the main user being created after
+ // BMS, which can happen for the first ever boot of a new device.
+ mService = new BackupManagerServiceTestable(mContextMock);
+ mServiceLifecycle = new BackupManagerService.Lifecycle(mContextMock, mService);
+ when(mUserManagerMock.getMainUser()).thenReturn(UserHandle.of(NON_SYSTEM_USER));
+ assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
+
+ simulateUserUnlocked(UserHandle.USER_SYSTEM);
+
+ assertTrue(mService.isBackupServiceActive(NON_SYSTEM_USER));
+ }
+
+ @Test
+ public void onUserUnlocking_mainUserChanged_firstUnlockAfterReboot_doesNotStartForSystemUser() {
+ // Create BMS *before* setting a main user to simulate the main user being created after
+ // BMS, which can happen for the first ever boot of a new device.
+ mService = new BackupManagerServiceTestable(mContextMock);
+ mServiceLifecycle = new BackupManagerService.Lifecycle(mContextMock, mService);
+ when(mUserManagerMock.getMainUser()).thenReturn(UserHandle.of(NON_SYSTEM_USER));
+ assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
+
+ simulateUserUnlocked(UserHandle.USER_SYSTEM);
+
+ assertFalse(mService.isUserReadyForBackup(UserHandle.USER_SYSTEM));
+ }
+
+ @Test
+ public void onUserUnlocking_mainUserChanged_secondUnlockAfterReboot_doesNotUpdateDefaultUser() {
+ // Create BMS *before* setting a main user to simulate the main user being created after
+ // BMS, which can happen for the first ever boot of a new device.
+ createBackupManagerServiceAndUnlockSystemUser();
+ when(mUserManagerMock.getMainUser()).thenReturn(UserHandle.of(NON_SYSTEM_USER));
+ assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
+
+ simulateUserUnlocked(NON_SYSTEM_USER);
+
+ assertFalse(mService.isBackupServiceActive(NON_SYSTEM_USER));
+ }
+
+ private void createBackupManagerServiceAndUnlockSystemUser() {
+ mService = new BackupManagerServiceTestable(mContextMock);
+ mServiceLifecycle = new BackupManagerService.Lifecycle(mContextMock, mService);
+ simulateUserUnlocked(UserHandle.USER_SYSTEM);
+ }
+
/**
* The 'default' user is set in the constructor of {@link BackupManagerService} so we need to
* start a new service after mocking the 'main' user.
*/
- private void setMockMainUserAndStartNewBackupManagerService(int userId) {
+ private void setMockMainUserAndCreateBackupManagerService(int userId) {
when(mUserManagerMock.getMainUser()).thenReturn(UserHandle.of(userId));
- mService = new BackupManagerServiceTestable(mContextMock, mUserServices);
+ mService = new BackupManagerServiceTestable(mContextMock);
+ mServiceLifecycle = new BackupManagerService.Lifecycle(mContextMock, mService);
}
private void simulateUserUnlocked(int userId) {
ConditionVariable unlocked = new ConditionVariable(false);
- mService.onUnlockUser(userId);
+ mServiceLifecycle.onUserUnlocking(
+ new SystemService.TargetUser(
+ new UserInfo(userId, /* name= */ "test", /* flags= */ 0)));
mService.getBackupHandler().post(unlocked::open);
unlocked.block();
when(mUserManagerMock.isUserUnlocked(userId)).thenReturn(true);
@@ -672,9 +759,8 @@
static int sCallingUid = -1;
static UserManager sUserManagerMock = null;
- BackupManagerServiceTestable(
- Context context, SparseArray<UserBackupManagerService> userServices) {
- super(context, userServices);
+ BackupManagerServiceTestable(Context context) {
+ super(context);
}
@Override
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 819b0b2..66711df 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -18038,6 +18038,87 @@
public static final int CELL_BROADCAST_RESULT_FAIL_ACTIVATION = 3;
/**
+ * Callback mode type
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"EMERGENCY_CALLBACK_MODE_"}, value = {
+ EMERGENCY_CALLBACK_MODE_CALL,
+ EMERGENCY_CALLBACK_MODE_SMS})
+ public @interface EmergencyCallbackModeType {}
+
+ /**
+ * The callback mode is due to emergency call.
+ * @hide
+ */
+ public static final int EMERGENCY_CALLBACK_MODE_CALL = 1;
+
+ /**
+ * The callback mode is due to emergency SMS.
+ * @hide
+ */
+ public static final int EMERGENCY_CALLBACK_MODE_SMS = 2;
+
+ /**
+ * The reason for changing callback mode.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"STOP_REASON_"},
+ value = {
+ STOP_REASON_UNKNOWN,
+ STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED,
+ STOP_REASON_NORMAL_SMS_SENT,
+ STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED,
+ STOP_REASON_EMERGENCY_SMS_SENT,
+ STOP_REASON_TIMER_EXPIRED,
+ STOP_REASON_USER_ACTION,
+ })
+ public @interface EmergencyCallbackModeStopReason {}
+
+ /**
+ * unknown reason.
+ * @hide
+ */
+ public static final int STOP_REASON_UNKNOWN = 0;
+
+ /**
+ * The call back mode is exited due to a new normal call is originated.
+ * @hide
+ */
+ public static final int STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED = 1;
+
+ /**
+ * The call back mode is exited due to a new normal SMS is originated.
+ * @hide
+ */
+ public static final int STOP_REASON_NORMAL_SMS_SENT = 2;
+
+ /**
+ * The call back mode is exited due to a new emergency call is originated.
+ * @hide
+ */
+ public static final int STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED = 3;
+
+ /**
+ * The call back mode is exited due to a new emergency SMS is originated.
+ * @hide
+ */
+ public static final int STOP_REASON_EMERGENCY_SMS_SENT = 4;
+
+ /**
+ * The call back mode is exited due to timer expiry.
+ * @hide
+ */
+ public static final int STOP_REASON_TIMER_EXPIRED = 5;
+
+ /**
+ * The call back mode is exited due to user action.
+ * @hide
+ */
+ public static final int STOP_REASON_USER_ACTION = 6;
+
+ /**
* Set reception of cell broadcast messages with the list of the given ranges
*
* <p>The ranges set previously will be overridden by the new one. Empty list
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index 74b42d4..9593c8a 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -340,16 +340,18 @@
* Send command to the implementation of {@link SharedConnectivityService} requesting
* disconnection from the active Tether Network.
*
+ * @param network {@link TetherNetwork} object representing the network the user has requested
+ * to disconnect from.
* @return Returns true if the service received the command. Does not guarantee that the
* disconnection was successful.
*/
- public boolean disconnectTetherNetwork() {
+ public boolean disconnectTetherNetwork(@NonNull TetherNetwork network) {
if (mService == null) {
return false;
}
try {
- mService.disconnectTetherNetwork();
+ mService.disconnectTetherNetwork(network);
} catch (RemoteException e) {
Log.e(TAG, "Exception in disconnectTetherNetwork", e);
return false;
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl
index 5d79405..52da596 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/ISharedConnectivityService.aidl
@@ -27,7 +27,7 @@
void registerCallback(in ISharedConnectivityCallback callback);
void unregisterCallback(in ISharedConnectivityCallback callback);
void connectTetherNetwork(in TetherNetwork network);
- void disconnectTetherNetwork();
+ void disconnectTetherNetwork(in TetherNetwork network);
void connectKnownNetwork(in KnownNetwork network);
void forgetKnownNetwork(in KnownNetwork network);
}
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
index a0b931f..13084f4 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
@@ -117,9 +117,9 @@
}
@Override
- public void disconnectTetherNetwork() {
+ public void disconnectTetherNetwork(TetherNetwork network) {
checkPermissions();
- mHandler.post(() -> onDisconnectTetherNetwork());
+ mHandler.post(() -> onDisconnectTetherNetwork(network));
}
@Override
@@ -323,8 +323,10 @@
* Implementing application should implement this method.
*
* Implementation should initiate a disconnection from the active Tether Network.
+ *
+ * @param network Object identifying the Tether Network the user has requested to disconnect.
*/
- public abstract void onDisconnectTetherNetwork();
+ public abstract void onDisconnectTetherNetwork(@NonNull TetherNetwork network);
/**
* Implementing application should implement this method.
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
index 815a012..439d456 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
@@ -285,25 +285,28 @@
*/
@Test
public void disconnectTetherNetwork_serviceNotConnected_shouldFail() {
+ TetherNetwork network = buildTetherNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
- assertFalse(manager.disconnectTetherNetwork());
+ assertFalse(manager.disconnectTetherNetwork(network));
}
@Test
public void disconnectTetherNetwork() throws RemoteException {
+ TetherNetwork network = buildTetherNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
- manager.disconnectTetherNetwork();
- verify(mService).disconnectTetherNetwork();
+ manager.disconnectTetherNetwork(network);
+ verify(mService).disconnectTetherNetwork(network);
}
@Test
public void disconnectTetherNetwork_remoteException_shouldFail() throws RemoteException {
+ TetherNetwork network = buildTetherNetwork();
SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
- doThrow(new RemoteException()).when(mService).disconnectTetherNetwork();
- assertFalse(manager.disconnectTetherNetwork());
+ doThrow(new RemoteException()).when(mService).disconnectTetherNetwork(any());
+ assertFalse(manager.disconnectTetherNetwork(network));
}
/**
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
index e15be8b..fb8d7bf 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityServiceTest.java
@@ -56,7 +56,7 @@
public void onConnectTetherNetwork(TetherNetwork network) {}
@Override
- public void onDisconnectTetherNetwork() {}
+ public void onDisconnectTetherNetwork(TetherNetwork network) {}
@Override
public void onConnectKnownNetwork(KnownNetwork network) {}