Merge "Extract out IMM.DelegateImpl#onViewFocusChanged()"
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index 2682dd7..442c130 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -36,9 +36,11 @@
/**
* Cancel the jobs for a given uid (e.g. when app data is cleared)
+ *
+ * @param includeProxiedJobs Include jobs scheduled for this UID by other apps
*/
- void cancelJobsForUid(int uid, @JobParameters.StopReason int reason, int debugReasonCode,
- String debugReason);
+ void cancelJobsForUid(int uid, boolean includeProxiedJobs,
+ @JobParameters.StopReason int reason, int debugReasonCode, String debugReason);
/**
* These are for activity manager to communicate to use what is currently performing backups.
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 f5c0ed9..bdd1fc54 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -970,12 +970,12 @@
// Has this package scheduled any jobs, such that we will take action
// if it were to be force-stopped?
if (pkgUid != -1) {
- List<JobStatus> jobsForUid;
+ ArraySet<JobStatus> jobsForUid;
synchronized (mLock) {
jobsForUid = mJobs.getJobsByUid(pkgUid);
}
for (int i = jobsForUid.size() - 1; i >= 0; i--) {
- if (jobsForUid.get(i).getSourcePackageName().equals(pkgName)) {
+ if (jobsForUid.valueAt(i).getSourcePackageName().equals(pkgName)) {
if (DEBUG) {
Slog.d(TAG, "Restart query: package " + pkgName + " at uid "
+ pkgUid + " has jobs");
@@ -1292,10 +1292,11 @@
public List<JobInfo> getPendingJobs(int uid) {
synchronized (mLock) {
- List<JobStatus> jobs = mJobs.getJobsByUid(uid);
+ ArraySet<JobStatus> jobs = mJobs.getJobsByUid(uid);
ArrayList<JobInfo> outList = new ArrayList<JobInfo>(jobs.size());
+ // Write out for loop to avoid addAll() creating an Iterator.
for (int i = jobs.size() - 1; i >= 0; i--) {
- JobStatus job = jobs.get(i);
+ final JobStatus job = jobs.valueAt(i);
outList.add(job.getJob());
}
return outList;
@@ -1304,9 +1305,9 @@
public JobInfo getPendingJob(int uid, int jobId) {
synchronized (mLock) {
- List<JobStatus> jobs = mJobs.getJobsByUid(uid);
+ ArraySet<JobStatus> jobs = mJobs.getJobsByUid(uid);
for (int i = jobs.size() - 1; i >= 0; i--) {
- JobStatus job = jobs.get(i);
+ JobStatus job = jobs.valueAt(i);
if (job.getJobId() == jobId) {
return job.getJob();
}
@@ -1348,7 +1349,7 @@
Slog.wtfStack(TAG, "Can't cancel all jobs for system package");
return;
}
- final List<JobStatus> jobsForUid = new ArrayList<>();
+ final ArraySet<JobStatus> jobsForUid = new ArraySet<>();
if (includeSchedulingApp) {
mJobs.getJobsByUid(uid, jobsForUid);
}
@@ -1356,7 +1357,7 @@
mJobs.getJobsBySourceUid(uid, jobsForUid);
}
for (int i = jobsForUid.size() - 1; i >= 0; i--) {
- final JobStatus job = jobsForUid.get(i);
+ final JobStatus job = jobsForUid.valueAt(i);
final boolean shouldCancel =
(includeSchedulingApp
&& job.getServiceComponent().getPackageName().equals(pkgName))
@@ -1368,14 +1369,16 @@
}
/**
- * Entry point from client to cancel all jobs originating from their uid.
+ * Entry point from client to cancel all jobs scheduled for or from their uid.
* This will remove the job from the master list, and cancel the job if it was staged for
* execution or being executed.
*
* @param uid Uid to check against for removal of a job.
+ * @param includeSourceApp Whether to include jobs scheduled for this UID by another UID.
+ * If false, only jobs scheduled by this UID will be cancelled.
*/
- public boolean cancelJobsForUid(int uid, @JobParameters.StopReason int reason,
- int internalReasonCode, String debugReason) {
+ public boolean cancelJobsForUid(int uid, boolean includeSourceApp,
+ @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
if (uid == Process.SYSTEM_UID) {
Slog.wtfStack(TAG, "Can't cancel all jobs for system uid");
return false;
@@ -1383,9 +1386,15 @@
boolean jobsCanceled = false;
synchronized (mLock) {
- final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
+ final ArraySet<JobStatus> jobsForUid = new ArraySet<>();
+ // Get jobs scheduled by the app.
+ mJobs.getJobsByUid(uid, jobsForUid);
+ if (includeSourceApp) {
+ // Get jobs scheduled for the app by someone else.
+ mJobs.getJobsBySourceUid(uid, jobsForUid);
+ }
for (int i = 0; i < jobsForUid.size(); i++) {
- JobStatus toRemove = jobsForUid.get(i);
+ JobStatus toRemove = jobsForUid.valueAt(i);
cancelJobImplLocked(toRemove, null, reason, internalReasonCode, debugReason);
jobsCanceled = true;
}
@@ -2220,6 +2229,7 @@
updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
if (disabled) {
cancelJobsForUid(uid,
+ /* includeSourceApp */ true,
JobParameters.STOP_REASON_BACKGROUND_RESTRICTION,
JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
"uid gone");
@@ -2241,6 +2251,7 @@
final boolean disabled = message.arg2 != 0;
if (disabled) {
cancelJobsForUid(uid,
+ /* includeSourceApp */ true,
JobParameters.STOP_REASON_BACKGROUND_RESTRICTION,
JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
"app uid idle");
@@ -2899,9 +2910,10 @@
}
@Override
- public void cancelJobsForUid(int uid, @JobParameters.StopReason int reason,
- int internalReasonCode, String debugReason) {
- JobSchedulerService.this.cancelJobsForUid(uid, reason, internalReasonCode, debugReason);
+ public void cancelJobsForUid(int uid, boolean includeProxiedJobs,
+ @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
+ JobSchedulerService.this.cancelJobsForUid(uid,
+ includeProxiedJobs, reason, internalReasonCode, debugReason);
}
@Override
@@ -3273,6 +3285,8 @@
final long ident = Binder.clearCallingIdentity();
try {
JobSchedulerService.this.cancelJobsForUid(uid,
+ // Documentation says only jobs scheduled BY the app will be cancelled
+ /* includeSourceApp */ false,
JobParameters.STOP_REASON_CANCELLED_BY_APP,
JobParameters.INTERNAL_STOP_REASON_CANCELED,
"cancelAll() called by app, callingUid=" + uid);
@@ -3484,7 +3498,9 @@
if (!hasJobId) {
pw.println("Canceling all jobs for " + pkgName + " in user " + userId);
- if (!cancelJobsForUid(pkgUid, JobParameters.STOP_REASON_USER,
+ if (!cancelJobsForUid(pkgUid,
+ /* includeSourceApp */ false,
+ JobParameters.STOP_REASON_USER,
JobParameters.INTERNAL_STOP_REASON_CANCELED,
"cancel shell command for package")) {
pw.println("No matching jobs found.");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index ff4d26d..f731b8d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -291,11 +291,11 @@
* @return A list of all the jobs scheduled for the source app. Never null.
*/
@NonNull
- public List<JobStatus> getJobsBySourceUid(int sourceUid) {
+ public ArraySet<JobStatus> getJobsBySourceUid(int sourceUid) {
return mJobSet.getJobsBySourceUid(sourceUid);
}
- public void getJobsBySourceUid(int sourceUid, @NonNull List<JobStatus> insertInto) {
+ public void getJobsBySourceUid(int sourceUid, @NonNull Set<JobStatus> insertInto) {
mJobSet.getJobsBySourceUid(sourceUid, insertInto);
}
@@ -304,11 +304,11 @@
* @return All JobStatus objects for a given uid from the master list. Never null.
*/
@NonNull
- public List<JobStatus> getJobsByUid(int uid) {
+ public ArraySet<JobStatus> getJobsByUid(int uid) {
return mJobSet.getJobsByUid(uid);
}
- public void getJobsByUid(int uid, @NonNull List<JobStatus> insertInto) {
+ public void getJobsByUid(int uid, @NonNull Set<JobStatus> insertInto) {
mJobSet.getJobsByUid(uid, insertInto);
}
@@ -1232,13 +1232,13 @@
mJobsPerSourceUid = new SparseArray<>();
}
- public List<JobStatus> getJobsByUid(int uid) {
- ArrayList<JobStatus> matchingJobs = new ArrayList<JobStatus>();
+ public ArraySet<JobStatus> getJobsByUid(int uid) {
+ ArraySet<JobStatus> matchingJobs = new ArraySet<>();
getJobsByUid(uid, matchingJobs);
return matchingJobs;
}
- public void getJobsByUid(int uid, List<JobStatus> insertInto) {
+ public void getJobsByUid(int uid, Set<JobStatus> insertInto) {
ArraySet<JobStatus> jobs = mJobs.get(uid);
if (jobs != null) {
insertInto.addAll(jobs);
@@ -1246,13 +1246,13 @@
}
@NonNull
- public List<JobStatus> getJobsBySourceUid(int sourceUid) {
- final ArrayList<JobStatus> result = new ArrayList<JobStatus>();
+ public ArraySet<JobStatus> getJobsBySourceUid(int sourceUid) {
+ final ArraySet<JobStatus> result = new ArraySet<>();
getJobsBySourceUid(sourceUid, result);
return result;
}
- public void getJobsBySourceUid(int sourceUid, List<JobStatus> insertInto) {
+ public void getJobsBySourceUid(int sourceUid, Set<JobStatus> insertInto) {
final ArraySet<JobStatus> jobs = mJobsPerSourceUid.get(sourceUid);
if (jobs != null) {
insertInto.addAll(jobs);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
index 9c16772..bbd661a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
@@ -50,7 +50,6 @@
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
import java.util.function.Predicate;
/**
@@ -397,10 +396,10 @@
return;
}
final long nowElapsed = sElapsedRealtimeClock.millis();
- List<JobStatus> jobsByUid = mService.getJobStore().getJobsByUid(uid);
+ ArraySet<JobStatus> jobsByUid = mService.getJobStore().getJobsBySourceUid(uid);
boolean hasPrefetch = false;
for (int i = 0; i < jobsByUid.size(); i++) {
- JobStatus js = jobsByUid.get(i);
+ JobStatus js = jobsByUid.valueAt(i);
if (js.hasFlexibilityConstraint()) {
js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js));
hasPrefetch |= js.getJob().isPrefetch();
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 0f7e01b..94275ae 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -31,8 +31,6 @@
import android.os.ServiceManager;
import android.os.UserHandle;
-import com.android.server.SystemConfig;
-
import java.util.List;
/**
@@ -50,7 +48,7 @@
* <overlayable name="OverlayableResourcesName" actor="overlay://namespace/actorName">
* }</pre></p>
*
- * <p>Actors are defined through {@link SystemConfig}. Only system packages can be used.
+ * <p>Actors are defined through SystemConfig. Only system packages can be used.
* The namespace "android" is reserved for use by AOSP and any "android" definitions must
* have an implementation on device that fulfill their intended functionality.</p>
*
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index e13f60c..2c28268 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -45,7 +45,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Parcelling;
import com.android.internal.util.Parcelling.BuiltIn.ForBoolean;
-import com.android.server.SystemConfig;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -803,7 +802,6 @@
*/
public static final int PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE = 1 << 2;
-
/**
* If false, {@link android.view.KeyEvent#KEYCODE_BACK} related events will be forwarded to
* the Activities, Dialogs and Views and {@link android.app.Activity#onBackPressed()},
@@ -815,12 +813,24 @@
*/
public static final int PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK = 1 << 3;
+ /**
+ * Whether or not this package is allowed to access hidden APIs. Replacement for legacy
+ * implementation of {@link #isPackageWhitelistedForHiddenApis()}.
+ *
+ * This is an internal flag and should never be used outside of this class. The real API for
+ * the hidden API enforcement policy is {@link #getHiddenApiEnforcementPolicy()}.
+ *
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS = 1 << 4;
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_EXT_" }, value = {
PRIVATE_FLAG_EXT_PROFILEABLE,
PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION,
PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE,
PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK,
+ PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoPrivateFlagsExt {}
@@ -2222,7 +2232,7 @@
}
private boolean isPackageWhitelistedForHiddenApis() {
- return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName);
+ return (privateFlagsExt & PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS) != 0;
}
/**
diff --git a/core/java/android/credentials/ui/RequestInfo.java b/core/java/android/credentials/ui/RequestInfo.java
index eddb519..5de6d73 100644
--- a/core/java/android/credentials/ui/RequestInfo.java
+++ b/core/java/android/credentials/ui/RequestInfo.java
@@ -36,6 +36,12 @@
*/
public static final @NonNull String EXTRA_REQUEST_INFO =
"android.credentials.ui.extra.REQUEST_INFO";
+ /**
+ * The intent extra key for the {@code ResultReceiver} object when launching the UX
+ * activities.
+ */
+ public static final @NonNull String EXTRA_RESULT_RECEIVER =
+ "android.credentials.ui.extra.RESULT_RECEIVER";
/** Type value for an executeGetCredential request. */
public static final @NonNull String TYPE_GET = "android.credentials.ui.TYPE_GET";
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 861a850..8873807 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2609,31 +2609,31 @@
* <table>
* <thead>
* <tr>
- * <th align="left">Input Format</th>
- * <th align="left">Output Format</th>
- * <th align="left">Capability</th>
+ * <th style="text-align: left;">Input Format</th>
+ * <th style="text-align: left;">Output Format</th>
+ * <th style="text-align: left;">Capability</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td>
- * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td>
- * <td align="left">PRIVATE_REPROCESSING</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#PRIVATE }</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#JPEG }</td>
+ * <td style="text-align: left;">PRIVATE_REPROCESSING</td>
* </tr>
* <tr>
- * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td>
- * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
- * <td align="left">PRIVATE_REPROCESSING</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#PRIVATE }</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+ * <td style="text-align: left;">PRIVATE_REPROCESSING</td>
* </tr>
* <tr>
- * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
- * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td>
- * <td align="left">YUV_REPROCESSING</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#JPEG }</td>
+ * <td style="text-align: left;">YUV_REPROCESSING</td>
* </tr>
* <tr>
- * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
- * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
- * <td align="left">YUV_REPROCESSING</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+ * <td style="text-align: left;">YUV_REPROCESSING</td>
* </tr>
* </tbody>
* </table>
@@ -2650,26 +2650,26 @@
* <table>
* <thead>
* <tr>
- * <th align="left">Input Format</th>
- * <th align="left">Output Format</th>
- * <th align="left">Capability</th>
+ * <th style="text-align: left;">Input Format</th>
+ * <th style="text-align: left;">Output Format</th>
+ * <th style="text-align: left;">Capability</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td>
- * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
- * <td align="left">PRIVATE_REPROCESSING</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#PRIVATE }</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#Y8 }</td>
+ * <td style="text-align: left;">PRIVATE_REPROCESSING</td>
* </tr>
* <tr>
- * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
- * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td>
- * <td align="left">YUV_REPROCESSING</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#Y8 }</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#JPEG }</td>
+ * <td style="text-align: left;">YUV_REPROCESSING</td>
* </tr>
* <tr>
- * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
- * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td>
- * <td align="left">YUV_REPROCESSING</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#Y8 }</td>
+ * <td style="text-align: left;">{@link android.graphics.ImageFormat#Y8 }</td>
+ * <td style="text-align: left;">YUV_REPROCESSING</td>
* </tr>
* </tbody>
* </table>
@@ -2705,60 +2705,60 @@
* <table>
* <thead>
* <tr>
- * <th align="center">Format</th>
- * <th align="center">Size</th>
- * <th align="center">Hardware Level</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">Format</th>
+ * <th style="text-align: center;">Size</th>
+ * <th style="text-align: center;">Hardware Level</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">JPEG</td>
- * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
- * <td align="center">Any</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td align="center">JPEG</td>
- * <td align="center">1920x1080 (1080p)</td>
- * <td align="center">Any</td>
- * <td align="center">if 1080p <= activeArraySize</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">1920x1080 (1080p)</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;">if 1080p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">JPEG</td>
- * <td align="center">1280x720 (720)</td>
- * <td align="center">Any</td>
- * <td align="center">if 720p <= activeArraySize</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">1280x720 (720)</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;">if 720p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">JPEG</td>
- * <td align="center">640x480 (480p)</td>
- * <td align="center">Any</td>
- * <td align="center">if 480p <= activeArraySize</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">640x480 (480p)</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;">if 480p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">JPEG</td>
- * <td align="center">320x240 (240p)</td>
- * <td align="center">Any</td>
- * <td align="center">if 240p <= activeArraySize</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">320x240 (240p)</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;">if 240p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">YUV_420_888</td>
- * <td align="center">all output sizes available for JPEG</td>
- * <td align="center">FULL</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">YUV_420_888</td>
+ * <td style="text-align: center;">all output sizes available for JPEG</td>
+ * <td style="text-align: center;">FULL</td>
+ * <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td align="center">YUV_420_888</td>
- * <td align="center">all output sizes available for JPEG, up to the maximum video size</td>
- * <td align="center">LIMITED</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">YUV_420_888</td>
+ * <td style="text-align: center;">all output sizes available for JPEG, up to the maximum video size</td>
+ * <td style="text-align: center;">LIMITED</td>
+ * <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td align="center">IMPLEMENTATION_DEFINED</td>
- * <td align="center">same as YUV_420_888</td>
- * <td align="center">Any</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">IMPLEMENTATION_DEFINED</td>
+ * <td style="text-align: center;">same as YUV_420_888</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;"></td>
* </tr>
* </tbody>
* </table>
@@ -2773,66 +2773,66 @@
* <table>
* <thead>
* <tr>
- * <th align="center">Format</th>
- * <th align="center">Size</th>
- * <th align="center">Hardware Level</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">Format</th>
+ * <th style="text-align: center;">Size</th>
+ * <th style="text-align: center;">Hardware Level</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">JPEG</td>
- * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
- * <td align="center">Any</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td align="center">JPEG</td>
- * <td align="center">1920x1080 (1080p)</td>
- * <td align="center">Any</td>
- * <td align="center">if 1080p <= activeArraySize</td>
+ * <td style="text-align: center;">JPEG</td>
+ * <td style="text-align: center;">1920x1080 (1080p)</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;">if 1080p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">YUV_420_888</td>
- * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
- * <td align="center">FULL</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">YUV_420_888</td>
+ * <td style="text-align: center;">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+ * <td style="text-align: center;">FULL</td>
+ * <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td align="center">YUV_420_888</td>
- * <td align="center">1920x1080 (1080p)</td>
- * <td align="center">FULL</td>
- * <td align="center">if 1080p <= activeArraySize</td>
+ * <td style="text-align: center;">YUV_420_888</td>
+ * <td style="text-align: center;">1920x1080 (1080p)</td>
+ * <td style="text-align: center;">FULL</td>
+ * <td style="text-align: center;">if 1080p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">YUV_420_888</td>
- * <td align="center">1280x720 (720)</td>
- * <td align="center">FULL</td>
- * <td align="center">if 720p <= activeArraySize</td>
+ * <td style="text-align: center;">YUV_420_888</td>
+ * <td style="text-align: center;">1280x720 (720)</td>
+ * <td style="text-align: center;">FULL</td>
+ * <td style="text-align: center;">if 720p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">YUV_420_888</td>
- * <td align="center">640x480 (480p)</td>
- * <td align="center">FULL</td>
- * <td align="center">if 480p <= activeArraySize</td>
+ * <td style="text-align: center;">YUV_420_888</td>
+ * <td style="text-align: center;">640x480 (480p)</td>
+ * <td style="text-align: center;">FULL</td>
+ * <td style="text-align: center;">if 480p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">YUV_420_888</td>
- * <td align="center">320x240 (240p)</td>
- * <td align="center">FULL</td>
- * <td align="center">if 240p <= activeArraySize</td>
+ * <td style="text-align: center;">YUV_420_888</td>
+ * <td style="text-align: center;">320x240 (240p)</td>
+ * <td style="text-align: center;">FULL</td>
+ * <td style="text-align: center;">if 240p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">YUV_420_888</td>
- * <td align="center">all output sizes available for FULL hardware level, up to the maximum video size</td>
- * <td align="center">LIMITED</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">YUV_420_888</td>
+ * <td style="text-align: center;">all output sizes available for FULL hardware level, up to the maximum video size</td>
+ * <td style="text-align: center;">LIMITED</td>
+ * <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td align="center">IMPLEMENTATION_DEFINED</td>
- * <td align="center">same as YUV_420_888</td>
- * <td align="center">Any</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">IMPLEMENTATION_DEFINED</td>
+ * <td style="text-align: center;">same as YUV_420_888</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;"></td>
* </tr>
* </tbody>
* </table>
@@ -2987,66 +2987,66 @@
* <table>
* <thead>
* <tr>
- * <th align="center">Format</th>
- * <th align="center">Size</th>
- * <th align="center">Hardware Level</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">Format</th>
+ * <th style="text-align: center;">Size</th>
+ * <th style="text-align: center;">Hardware Level</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td>
- * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} (*1)</td>
- * <td align="center">Any</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">{@link android.graphics.ImageFormat#JPEG }</td>
+ * <td style="text-align: center;">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} (*1)</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td>
- * <td align="center">1920x1080 (1080p)</td>
- * <td align="center">Any</td>
- * <td align="center">if 1080p <= activeArraySize</td>
+ * <td style="text-align: center;">{@link android.graphics.ImageFormat#JPEG }</td>
+ * <td style="text-align: center;">1920x1080 (1080p)</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;">if 1080p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
- * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
- * <td align="center">FULL</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+ * <td style="text-align: center;">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+ * <td style="text-align: center;">FULL</td>
+ * <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
- * <td align="center">1920x1080 (1080p)</td>
- * <td align="center">FULL</td>
- * <td align="center">if 1080p <= activeArraySize</td>
+ * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+ * <td style="text-align: center;">1920x1080 (1080p)</td>
+ * <td style="text-align: center;">FULL</td>
+ * <td style="text-align: center;">if 1080p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
- * <td align="center">1280x720 (720)</td>
- * <td align="center">FULL</td>
- * <td align="center">if 720p <= activeArraySize</td>
+ * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+ * <td style="text-align: center;">1280x720 (720)</td>
+ * <td style="text-align: center;">FULL</td>
+ * <td style="text-align: center;">if 720p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
- * <td align="center">640x480 (480p)</td>
- * <td align="center">FULL</td>
- * <td align="center">if 480p <= activeArraySize</td>
+ * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+ * <td style="text-align: center;">640x480 (480p)</td>
+ * <td style="text-align: center;">FULL</td>
+ * <td style="text-align: center;">if 480p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
- * <td align="center">320x240 (240p)</td>
- * <td align="center">FULL</td>
- * <td align="center">if 240p <= activeArraySize</td>
+ * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+ * <td style="text-align: center;">320x240 (240p)</td>
+ * <td style="text-align: center;">FULL</td>
+ * <td style="text-align: center;">if 240p <= activeArraySize</td>
* </tr>
* <tr>
- * <td align="center">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
- * <td align="center">all output sizes available for FULL hardware level, up to the maximum video size</td>
- * <td align="center">LIMITED</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">{@link android.graphics.ImageFormat#YUV_420_888 }</td>
+ * <td style="text-align: center;">all output sizes available for FULL hardware level, up to the maximum video size</td>
+ * <td style="text-align: center;">LIMITED</td>
+ * <td style="text-align: center;"></td>
* </tr>
* <tr>
- * <td align="center">{@link android.graphics.ImageFormat#PRIVATE }</td>
- * <td align="center">same as YUV_420_888</td>
- * <td align="center">Any</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">{@link android.graphics.ImageFormat#PRIVATE }</td>
+ * <td style="text-align: center;">same as YUV_420_888</td>
+ * <td style="text-align: center;">Any</td>
+ * <td style="text-align: center;"></td>
* </tr>
* </tbody>
* </table>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 3e1deb2..1a15596 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -990,18 +990,18 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center"></td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Camera device auto exposure algorithm is disabled</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Camera device auto exposure algorithm is disabled</td>
* </tr>
* </tbody>
* </table>
@@ -1009,120 +1009,120 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">Camera device initiates AE scan</td>
- * <td align="center">SEARCHING</td>
- * <td align="center">Values changing</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Camera device initiates AE scan</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">Values changing</td>
* </tr>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
- * <td align="center">LOCKED</td>
- * <td align="center">Values locked</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">Values locked</td>
* </tr>
* <tr>
- * <td align="center">SEARCHING</td>
- * <td align="center">Camera device finishes AE scan</td>
- * <td align="center">CONVERGED</td>
- * <td align="center">Good values, not changing</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">Camera device finishes AE scan</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Good values, not changing</td>
* </tr>
* <tr>
- * <td align="center">SEARCHING</td>
- * <td align="center">Camera device finishes AE scan</td>
- * <td align="center">FLASH_REQUIRED</td>
- * <td align="center">Converged but too dark w/o flash</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">Camera device finishes AE scan</td>
+ * <td style="text-align: center;">FLASH_REQUIRED</td>
+ * <td style="text-align: center;">Converged but too dark w/o flash</td>
* </tr>
* <tr>
- * <td align="center">SEARCHING</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
- * <td align="center">LOCKED</td>
- * <td align="center">Values locked</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">Values locked</td>
* </tr>
* <tr>
- * <td align="center">CONVERGED</td>
- * <td align="center">Camera device initiates AE scan</td>
- * <td align="center">SEARCHING</td>
- * <td align="center">Values changing</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Camera device initiates AE scan</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">Values changing</td>
* </tr>
* <tr>
- * <td align="center">CONVERGED</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
- * <td align="center">LOCKED</td>
- * <td align="center">Values locked</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">Values locked</td>
* </tr>
* <tr>
- * <td align="center">FLASH_REQUIRED</td>
- * <td align="center">Camera device initiates AE scan</td>
- * <td align="center">SEARCHING</td>
- * <td align="center">Values changing</td>
+ * <td style="text-align: center;">FLASH_REQUIRED</td>
+ * <td style="text-align: center;">Camera device initiates AE scan</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">Values changing</td>
* </tr>
* <tr>
- * <td align="center">FLASH_REQUIRED</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
- * <td align="center">LOCKED</td>
- * <td align="center">Values locked</td>
+ * <td style="text-align: center;">FLASH_REQUIRED</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">Values locked</td>
* </tr>
* <tr>
- * <td align="center">LOCKED</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
- * <td align="center">SEARCHING</td>
- * <td align="center">Values not good after unlock</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">Values not good after unlock</td>
* </tr>
* <tr>
- * <td align="center">LOCKED</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
- * <td align="center">CONVERGED</td>
- * <td align="center">Values good after unlock</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Values good after unlock</td>
* </tr>
* <tr>
- * <td align="center">LOCKED</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
- * <td align="center">FLASH_REQUIRED</td>
- * <td align="center">Exposure good, but too dark</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
+ * <td style="text-align: center;">FLASH_REQUIRED</td>
+ * <td style="text-align: center;">Exposure good, but too dark</td>
* </tr>
* <tr>
- * <td align="center">PRECAPTURE</td>
- * <td align="center">Sequence done. {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
- * <td align="center">CONVERGED</td>
- * <td align="center">Ready for high-quality capture</td>
+ * <td style="text-align: center;">PRECAPTURE</td>
+ * <td style="text-align: center;">Sequence done. {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is OFF</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Ready for high-quality capture</td>
* </tr>
* <tr>
- * <td align="center">PRECAPTURE</td>
- * <td align="center">Sequence done. {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
- * <td align="center">LOCKED</td>
- * <td align="center">Ready for high-quality capture</td>
+ * <td style="text-align: center;">PRECAPTURE</td>
+ * <td style="text-align: center;">Sequence done. {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} is ON</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">Ready for high-quality capture</td>
* </tr>
* <tr>
- * <td align="center">LOCKED</td>
- * <td align="center">aeLock is ON and aePrecaptureTrigger is START</td>
- * <td align="center">LOCKED</td>
- * <td align="center">Precapture trigger is ignored when AE is already locked</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">aeLock is ON and aePrecaptureTrigger is START</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">Precapture trigger is ignored when AE is already locked</td>
* </tr>
* <tr>
- * <td align="center">LOCKED</td>
- * <td align="center">aeLock is ON and aePrecaptureTrigger is CANCEL</td>
- * <td align="center">LOCKED</td>
- * <td align="center">Precapture trigger is ignored when AE is already locked</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">aeLock is ON and aePrecaptureTrigger is CANCEL</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">Precapture trigger is ignored when AE is already locked</td>
* </tr>
* <tr>
- * <td align="center">Any state (excluding LOCKED)</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START</td>
- * <td align="center">PRECAPTURE</td>
- * <td align="center">Start AE precapture metering sequence</td>
+ * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START</td>
+ * <td style="text-align: center;">PRECAPTURE</td>
+ * <td style="text-align: center;">Start AE precapture metering sequence</td>
* </tr>
* <tr>
- * <td align="center">Any state (excluding LOCKED)</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL</td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Currently active precapture metering sequence is canceled</td>
+ * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Currently active precapture metering sequence is canceled</td>
* </tr>
* </tbody>
* </table>
@@ -1138,54 +1138,54 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">Camera device finished AE scan</td>
- * <td align="center">CONVERGED</td>
- * <td align="center">Values are already good, transient states are skipped by camera device.</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Camera device finished AE scan</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Values are already good, transient states are skipped by camera device.</td>
* </tr>
* <tr>
- * <td align="center">Any state (excluding LOCKED)</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
- * <td align="center">FLASH_REQUIRED</td>
- * <td align="center">Converged but too dark w/o flash after a precapture sequence, transient states are skipped by camera device.</td>
+ * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
+ * <td style="text-align: center;">FLASH_REQUIRED</td>
+ * <td style="text-align: center;">Converged but too dark w/o flash after a precapture sequence, transient states are skipped by camera device.</td>
* </tr>
* <tr>
- * <td align="center">Any state (excluding LOCKED)</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
- * <td align="center">CONVERGED</td>
- * <td align="center">Converged after a precapture sequence, transient states are skipped by camera device.</td>
+ * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Converged after a precapture sequence, transient states are skipped by camera device.</td>
* </tr>
* <tr>
- * <td align="center">Any state (excluding LOCKED)</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
- * <td align="center">FLASH_REQUIRED</td>
- * <td align="center">Converged but too dark w/o flash after a precapture sequence is canceled, transient states are skipped by camera device.</td>
+ * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
+ * <td style="text-align: center;">FLASH_REQUIRED</td>
+ * <td style="text-align: center;">Converged but too dark w/o flash after a precapture sequence is canceled, transient states are skipped by camera device.</td>
* </tr>
* <tr>
- * <td align="center">Any state (excluding LOCKED)</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
- * <td align="center">CONVERGED</td>
- * <td align="center">Converged after a precapture sequences canceled, transient states are skipped by camera device.</td>
+ * <td style="text-align: center;">Any state (excluding LOCKED)</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Converged after a precapture sequences canceled, transient states are skipped by camera device.</td>
* </tr>
* <tr>
- * <td align="center">CONVERGED</td>
- * <td align="center">Camera device finished AE scan</td>
- * <td align="center">FLASH_REQUIRED</td>
- * <td align="center">Converged but too dark w/o flash after a new scan, transient states are skipped by camera device.</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Camera device finished AE scan</td>
+ * <td style="text-align: center;">FLASH_REQUIRED</td>
+ * <td style="text-align: center;">Converged but too dark w/o flash after a new scan, transient states are skipped by camera device.</td>
* </tr>
* <tr>
- * <td align="center">FLASH_REQUIRED</td>
- * <td align="center">Camera device finished AE scan</td>
- * <td align="center">CONVERGED</td>
- * <td align="center">Converged after a new scan, transient states are skipped by camera device.</td>
+ * <td style="text-align: center;">FLASH_REQUIRED</td>
+ * <td style="text-align: center;">Camera device finished AE scan</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Converged after a new scan, transient states are skipped by camera device.</td>
* </tr>
* </tbody>
* </table>
@@ -1413,18 +1413,18 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center"></td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Never changes</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Never changes</td>
* </tr>
* </tbody>
* </table>
@@ -1432,66 +1432,66 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">ACTIVE_SCAN</td>
- * <td align="center">Start AF sweep, Lens now moving</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">ACTIVE_SCAN</td>
+ * <td style="text-align: center;">Start AF sweep, Lens now moving</td>
* </tr>
* <tr>
- * <td align="center">ACTIVE_SCAN</td>
- * <td align="center">AF sweep done</td>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Focused, Lens now locked</td>
+ * <td style="text-align: center;">ACTIVE_SCAN</td>
+ * <td style="text-align: center;">AF sweep done</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Focused, Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">ACTIVE_SCAN</td>
- * <td align="center">AF sweep done</td>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Not focused, Lens now locked</td>
+ * <td style="text-align: center;">ACTIVE_SCAN</td>
+ * <td style="text-align: center;">AF sweep done</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Not focused, Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">ACTIVE_SCAN</td>
- * <td align="center">AF_CANCEL</td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Cancel/reset AF, Lens now locked</td>
+ * <td style="text-align: center;">ACTIVE_SCAN</td>
+ * <td style="text-align: center;">AF_CANCEL</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Cancel/reset AF, Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">AF_CANCEL</td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Cancel/reset AF</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_CANCEL</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Cancel/reset AF</td>
* </tr>
* <tr>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">ACTIVE_SCAN</td>
- * <td align="center">Start new sweep, Lens now moving</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">ACTIVE_SCAN</td>
+ * <td style="text-align: center;">Start new sweep, Lens now moving</td>
* </tr>
* <tr>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">AF_CANCEL</td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Cancel/reset AF</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_CANCEL</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Cancel/reset AF</td>
* </tr>
* <tr>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">ACTIVE_SCAN</td>
- * <td align="center">Start new sweep, Lens now moving</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">ACTIVE_SCAN</td>
+ * <td style="text-align: center;">Start new sweep, Lens now moving</td>
* </tr>
* <tr>
- * <td align="center">Any state</td>
- * <td align="center">Mode change</td>
- * <td align="center">INACTIVE</td>
- * <td align="center"></td>
+ * <td style="text-align: center;">Any state</td>
+ * <td style="text-align: center;">Mode change</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;"></td>
* </tr>
* </tbody>
* </table>
@@ -1504,36 +1504,36 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Focus is already good or good after a scan, lens is now locked.</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Focus is already good or good after a scan, lens is now locked.</td>
* </tr>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Focus failed after a scan, lens is now locked.</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Focus failed after a scan, lens is now locked.</td>
* </tr>
* <tr>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Focus is already good or good after a scan, lens is now locked.</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Focus is already good or good after a scan, lens is now locked.</td>
* </tr>
* <tr>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Focus is good after a scan, lens is not locked.</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Focus is good after a scan, lens is not locked.</td>
* </tr>
* </tbody>
* </table>
@@ -1541,102 +1541,102 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">Camera device initiates new scan</td>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">Start AF scan, Lens now moving</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Camera device initiates new scan</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">Start AF scan, Lens now moving</td>
* </tr>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">AF state query, Lens now locked</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF state query, Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">Camera device completes current scan</td>
- * <td align="center">PASSIVE_FOCUSED</td>
- * <td align="center">End AF scan, Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">Camera device completes current scan</td>
+ * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+ * <td style="text-align: center;">End AF scan, Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">Camera device fails current scan</td>
- * <td align="center">PASSIVE_UNFOCUSED</td>
- * <td align="center">End AF scan, Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">Camera device fails current scan</td>
+ * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+ * <td style="text-align: center;">End AF scan, Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Immediate transition, if focus is good. Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Immediate transition, if focus is good. Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Immediate transition, if focus is bad. Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Immediate transition, if focus is bad. Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">AF_CANCEL</td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Reset lens position, Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">AF_CANCEL</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Reset lens position, Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_FOCUSED</td>
- * <td align="center">Camera device initiates new scan</td>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">Start AF scan, Lens now moving</td>
+ * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+ * <td style="text-align: center;">Camera device initiates new scan</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">Start AF scan, Lens now moving</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_UNFOCUSED</td>
- * <td align="center">Camera device initiates new scan</td>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">Start AF scan, Lens now moving</td>
+ * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+ * <td style="text-align: center;">Camera device initiates new scan</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">Start AF scan, Lens now moving</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_FOCUSED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Immediate transition, lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Immediate transition, lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_UNFOCUSED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Immediate transition, lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Immediate transition, lens now locked</td>
* </tr>
* <tr>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">No effect</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">No effect</td>
* </tr>
* <tr>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">AF_CANCEL</td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Restart AF scan</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_CANCEL</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Restart AF scan</td>
* </tr>
* <tr>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">No effect</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">No effect</td>
* </tr>
* <tr>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">AF_CANCEL</td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Restart AF scan</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_CANCEL</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Restart AF scan</td>
* </tr>
* </tbody>
* </table>
@@ -1644,102 +1644,102 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">Camera device initiates new scan</td>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">Start AF scan, Lens now moving</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Camera device initiates new scan</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">Start AF scan, Lens now moving</td>
* </tr>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">AF state query, Lens now locked</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF state query, Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">Camera device completes current scan</td>
- * <td align="center">PASSIVE_FOCUSED</td>
- * <td align="center">End AF scan, Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">Camera device completes current scan</td>
+ * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+ * <td style="text-align: center;">End AF scan, Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">Camera device fails current scan</td>
- * <td align="center">PASSIVE_UNFOCUSED</td>
- * <td align="center">End AF scan, Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">Camera device fails current scan</td>
+ * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+ * <td style="text-align: center;">End AF scan, Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Eventual transition once the focus is good. Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Eventual transition once the focus is good. Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Eventual transition if cannot find focus. Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Eventual transition if cannot find focus. Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">AF_CANCEL</td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Reset lens position, Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">AF_CANCEL</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Reset lens position, Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_FOCUSED</td>
- * <td align="center">Camera device initiates new scan</td>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">Start AF scan, Lens now moving</td>
+ * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+ * <td style="text-align: center;">Camera device initiates new scan</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">Start AF scan, Lens now moving</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_UNFOCUSED</td>
- * <td align="center">Camera device initiates new scan</td>
- * <td align="center">PASSIVE_SCAN</td>
- * <td align="center">Start AF scan, Lens now moving</td>
+ * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+ * <td style="text-align: center;">Camera device initiates new scan</td>
+ * <td style="text-align: center;">PASSIVE_SCAN</td>
+ * <td style="text-align: center;">Start AF scan, Lens now moving</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_FOCUSED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_FOCUSED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Immediate trans. Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">PASSIVE_UNFOCUSED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. Lens now locked</td>
+ * <td style="text-align: center;">PASSIVE_UNFOCUSED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">Immediate trans. Lens now locked</td>
* </tr>
* <tr>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">No effect</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">No effect</td>
* </tr>
* <tr>
- * <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">AF_CANCEL</td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Restart AF scan</td>
+ * <td style="text-align: center;">FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_CANCEL</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Restart AF scan</td>
* </tr>
* <tr>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">AF_TRIGGER</td>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">No effect</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_TRIGGER</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">No effect</td>
* </tr>
* <tr>
- * <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">AF_CANCEL</td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Restart AF scan</td>
+ * <td style="text-align: center;">NOT_FOCUSED_LOCKED</td>
+ * <td style="text-align: center;">AF_CANCEL</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Restart AF scan</td>
* </tr>
* </tbody>
* </table>
@@ -1751,30 +1751,30 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">any state</td>
- * <td align="center">CAF-->AUTO mode switch</td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Mode switch without trigger, initial state must be INACTIVE</td>
+ * <td style="text-align: center;">any state</td>
+ * <td style="text-align: center;">CAF-->AUTO mode switch</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Mode switch without trigger, initial state must be INACTIVE</td>
* </tr>
* <tr>
- * <td align="center">any state</td>
- * <td align="center">CAF-->AUTO mode switch with AF_TRIGGER</td>
- * <td align="center">trigger-reachable states from INACTIVE</td>
- * <td align="center">Mode switch with trigger, INACTIVE is skipped</td>
+ * <td style="text-align: center;">any state</td>
+ * <td style="text-align: center;">CAF-->AUTO mode switch with AF_TRIGGER</td>
+ * <td style="text-align: center;">trigger-reachable states from INACTIVE</td>
+ * <td style="text-align: center;">Mode switch with trigger, INACTIVE is skipped</td>
* </tr>
* <tr>
- * <td align="center">any state</td>
- * <td align="center">AUTO-->CAF mode switch</td>
- * <td align="center">passively reachable states from INACTIVE</td>
- * <td align="center">Mode switch without trigger, passive transient state is skipped</td>
+ * <td style="text-align: center;">any state</td>
+ * <td style="text-align: center;">AUTO-->CAF mode switch</td>
+ * <td style="text-align: center;">passively reachable states from INACTIVE</td>
+ * <td style="text-align: center;">Mode switch without trigger, passive transient state is skipped</td>
* </tr>
* </tbody>
* </table>
@@ -2053,18 +2053,18 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center"></td>
- * <td align="center">INACTIVE</td>
- * <td align="center">Camera device auto white balance algorithm is disabled</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;"></td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Camera device auto white balance algorithm is disabled</td>
* </tr>
* </tbody>
* </table>
@@ -2072,54 +2072,54 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">Camera device initiates AWB scan</td>
- * <td align="center">SEARCHING</td>
- * <td align="center">Values changing</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Camera device initiates AWB scan</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">Values changing</td>
* </tr>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
- * <td align="center">LOCKED</td>
- * <td align="center">Values locked</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">Values locked</td>
* </tr>
* <tr>
- * <td align="center">SEARCHING</td>
- * <td align="center">Camera device finishes AWB scan</td>
- * <td align="center">CONVERGED</td>
- * <td align="center">Good values, not changing</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">Camera device finishes AWB scan</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Good values, not changing</td>
* </tr>
* <tr>
- * <td align="center">SEARCHING</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
- * <td align="center">LOCKED</td>
- * <td align="center">Values locked</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">Values locked</td>
* </tr>
* <tr>
- * <td align="center">CONVERGED</td>
- * <td align="center">Camera device initiates AWB scan</td>
- * <td align="center">SEARCHING</td>
- * <td align="center">Values changing</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Camera device initiates AWB scan</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">Values changing</td>
* </tr>
* <tr>
- * <td align="center">CONVERGED</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
- * <td align="center">LOCKED</td>
- * <td align="center">Values locked</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is ON</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">Values locked</td>
* </tr>
* <tr>
- * <td align="center">LOCKED</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is OFF</td>
- * <td align="center">SEARCHING</td>
- * <td align="center">Values not good after unlock</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is OFF</td>
+ * <td style="text-align: center;">SEARCHING</td>
+ * <td style="text-align: center;">Values not good after unlock</td>
* </tr>
* </tbody>
* </table>
@@ -2132,24 +2132,24 @@
* <table>
* <thead>
* <tr>
- * <th align="center">State</th>
- * <th align="center">Transition Cause</th>
- * <th align="center">New State</th>
- * <th align="center">Notes</th>
+ * <th style="text-align: center;">State</th>
+ * <th style="text-align: center;">Transition Cause</th>
+ * <th style="text-align: center;">New State</th>
+ * <th style="text-align: center;">Notes</th>
* </tr>
* </thead>
* <tbody>
* <tr>
- * <td align="center">INACTIVE</td>
- * <td align="center">Camera device finished AWB scan</td>
- * <td align="center">CONVERGED</td>
- * <td align="center">Values are already good, transient states are skipped by camera device.</td>
+ * <td style="text-align: center;">INACTIVE</td>
+ * <td style="text-align: center;">Camera device finished AWB scan</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Values are already good, transient states are skipped by camera device.</td>
* </tr>
* <tr>
- * <td align="center">LOCKED</td>
- * <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is OFF</td>
- * <td align="center">CONVERGED</td>
- * <td align="center">Values good after unlock, transient states are skipped by camera device.</td>
+ * <td style="text-align: center;">LOCKED</td>
+ * <td style="text-align: center;">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is OFF</td>
+ * <td style="text-align: center;">CONVERGED</td>
+ * <td style="text-align: center;">Values good after unlock, transient states are skipped by camera device.</td>
* </tr>
* </tbody>
* </table>
diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl
index 15e3ce2..61b24aa 100644
--- a/core/java/android/os/ISystemConfig.aidl
+++ b/core/java/android/os/ISystemConfig.aidl
@@ -47,4 +47,9 @@
* @see SystemConfigManager#getEnabledComponentOverrides
*/
List<ComponentName> getEnabledComponentOverrides(String packageName);
+
+ /**
+ * @see SystemConfigManager#getDefaultVrComponents
+ */
+ List<ComponentName> getDefaultVrComponents();
}
diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java
index cde2063..77843d9 100644
--- a/core/java/android/os/SystemConfigManager.java
+++ b/core/java/android/os/SystemConfigManager.java
@@ -147,4 +147,18 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Return the components that are enabled by default as VR mode listener services.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.QUERY_ALL_PACKAGES)
+ public List<ComponentName> getDefaultVrComponents() {
+ try {
+ return mInterface.getDefaultVrComponents();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return Collections.emptyList();
+ }
}
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index acf4da6..2cd9f89 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -257,6 +257,13 @@
return INSTALL_FAILED_CONTAINER_ERROR;
}
+ if (fsync(fd) < 0) {
+ ALOGE("Coulnd't fsync temporary file name: %s: %s\n", localTmpFileName, strerror(errno));
+ close(fd);
+ unlink(localTmpFileName);
+ return INSTALL_FAILED_INTERNAL_ERROR;
+ }
+
close(fd);
// Set the modification time for this file to the ZIP's mod time.
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index d8ea0a5..2d6e8f5 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -13,8 +13,6 @@
<option name="run-command" value="cmd window tracing level all" />
<!-- set WM tracing to frame (avoid incomplete states) -->
<option name="run-command" value="cmd window tracing frame" />
- <!-- set Layer tracing buffer size to 50mb -->
- <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 51200" />
<!-- ensure lock screen mode is swipe -->
<option name="run-command" value="locksettings set-disabled false" />
<!-- restart launcher to activate TAPL -->
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
index a207bf1..fa186c3 100644
--- a/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
+++ b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
@@ -304,13 +304,13 @@
for (int j = 0; j < NUM_EFFECTS; j++) {
effects[j] = new BassBoost(0, mSession);
effects[j].setControlStatusListener(mEffectListener);
- yield();
+ this.yield();
}
for (int j = NUM_EFFECTS - 1; j >= 0; j--) {
Log.w(TAG, "HammerReleaseTest releasing effect " + (Object) effects[j]);
effects[j].release();
effects[j] = null;
- yield();
+ this.yield();
}
}
Log.w(TAG, "HammerReleaseTest ended");
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
index dcfe11a..5d91a2e 100644
--- a/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
+++ b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
@@ -251,13 +251,13 @@
for (int i = 0; i < NUM_ITERATIONS; i++) {
for (int j = 0; j < NUM_EFFECTS; j++) {
effects[j] = new Visualizer(mSession);
- yield();
+ this.yield();
}
for (int j = NUM_EFFECTS - 1; j >= 0; j--) {
Log.w(TAG, "HammerReleaseTest releasing effect " + (Object) effects[j]);
effects[j].release();
effects[j] = null;
- yield();
+ this.yield();
}
}
Log.w(TAG, "HammerReleaseTest ended");
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_device.xml b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
index db54ae3..d4439f9 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_device.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
@@ -39,7 +39,6 @@
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingEnd="24dp"
- android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItemSmall"/>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialEntryUi.kt
new file mode 100644
index 0000000..96cc02f
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialEntryUi.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager
+
+import android.app.slice.Slice
+import android.credentials.ui.Entry
+import android.graphics.drawable.Icon
+
+/**
+ * UI representation for a credential entry used during the get credential flow.
+ *
+ * TODO: move to jetpack.
+ */
+class CredentialEntryUi(
+ val userName: CharSequence,
+ val displayName: CharSequence?,
+ val icon: Icon?,
+ // TODO: add last used.
+) {
+ companion object {
+ fun fromSlice(slice: Slice): CredentialEntryUi {
+ val items = slice.items
+
+ var title: String? = null
+ var subTitle: String? = null
+ var icon: Icon? = null
+
+ items.forEach {
+ if (it.hasHint(Entry.HINT_ICON)) {
+ icon = it.icon
+ } else if (it.hasHint(Entry.HINT_SUBTITLE)) {
+ subTitle = it.text.toString()
+ } else if (it.hasHint(Entry.HINT_TITLE)) {
+ title = it.text.toString()
+ }
+ }
+ // TODO: fail NPE more elegantly.
+ return CredentialEntryUi(title!!, subTitle, icon)
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index 46bf19c..8db547a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.credentialmanager
import android.app.slice.Slice
@@ -9,11 +25,8 @@
import android.credentials.ui.RequestInfo
import android.graphics.drawable.Icon
import android.os.Binder
-import com.android.credentialmanager.createflow.CreateOptionInfo
import com.android.credentialmanager.createflow.CreatePasskeyUiState
import com.android.credentialmanager.createflow.CreateScreenState
-import com.android.credentialmanager.createflow.ProviderInfo
-import com.android.credentialmanager.getflow.CredentialOptionInfo
import com.android.credentialmanager.getflow.GetCredentialUiState
import com.android.credentialmanager.getflow.GetScreenState
@@ -41,6 +54,39 @@
) ?: testProviderList()
}
+ fun getCredentialInitialUiState(): GetCredentialUiState {
+ val providerList = GetFlowUtils.toProviderList(providerList, context)
+ return GetCredentialUiState(
+ providerList,
+ GetScreenState.CREDENTIAL_SELECTION,
+ providerList.first()
+ )
+ }
+
+ fun createPasskeyInitialUiState(): CreatePasskeyUiState {
+ val providerList = CreateFlowUtils.toProviderList(providerList, context)
+ return CreatePasskeyUiState(
+ providers = providerList,
+ currentScreenState = CreateScreenState.PASSKEY_INTRO,
+ )
+ }
+
+ companion object {
+ lateinit var repo: CredentialManagerRepo
+
+ fun setup(
+ context: Context,
+ intent: Intent,
+ ) {
+ repo = CredentialManagerRepo(context, intent)
+ }
+
+ fun getInstance(): CredentialManagerRepo {
+ return repo
+ }
+ }
+
+ // TODO: below are prototype functionalities. To be removed for productionization.
private fun testProviderList(): List<ProviderData> {
return listOf(
ProviderData(
@@ -94,143 +140,4 @@
slice
)
}
-
- private fun getCredentialProviderList():
- List<com.android.credentialmanager.getflow.ProviderInfo> {
- return listOf(
- com.android.credentialmanager.getflow.ProviderInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- name = "Google Password Manager",
- appDomainName = "tribank.us",
- credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
- credentialOptions = listOf(
- CredentialOptionInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- title = "Elisa Backett",
- subtitle = "elisa.beckett@gmail.com",
- id = "id-1",
- ),
- CredentialOptionInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- title = "Elisa Backett Work",
- subtitle = "elisa.beckett.work@google.com",
- id = "id-2",
- ),
- )
- ),
- com.android.credentialmanager.getflow.ProviderInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- name = "Lastpass",
- appDomainName = "tribank.us",
- credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
- credentialOptions = listOf(
- CredentialOptionInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- title = "Elisa Backett",
- subtitle = "elisa.beckett@lastpass.com",
- id = "id-1",
- ),
- )
- ),
- com.android.credentialmanager.getflow.ProviderInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- name = "Dashlane",
- appDomainName = "tribank.us",
- credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
- credentialOptions = listOf(
- CredentialOptionInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- title = "Elisa Backett",
- subtitle = "elisa.beckett@dashlane.com",
- id = "id-1",
- ),
- )
- ),
- )
- }
-
- private fun createCredentialProviderList(): List<ProviderInfo> {
- return listOf(
- ProviderInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- name = "Google Password Manager",
- appDomainName = "tribank.us",
- credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
- createOptions = listOf(
- CreateOptionInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- title = "Elisa Backett",
- subtitle = "elisa.beckett@gmail.com",
- id = "id-1",
- ),
- CreateOptionInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- title = "Elisa Backett Work",
- subtitle = "elisa.beckett.work@google.com",
- id = "id-2",
- ),
- )
- ),
- ProviderInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- name = "Lastpass",
- appDomainName = "tribank.us",
- credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
- createOptions = listOf(
- CreateOptionInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- title = "Elisa Backett",
- subtitle = "elisa.beckett@lastpass.com",
- id = "id-1",
- ),
- )
- ),
- ProviderInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- name = "Dashlane",
- appDomainName = "tribank.us",
- credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
- createOptions = listOf(
- CreateOptionInfo(
- icon = context.getDrawable(R.drawable.ic_passkey)!!,
- title = "Elisa Backett",
- subtitle = "elisa.beckett@dashlane.com",
- id = "id-1",
- ),
- )
- ),
- )
- }
-
- fun getCredentialInitialUiState(): GetCredentialUiState {
- val providerList = getCredentialProviderList()
- return GetCredentialUiState(
- providerList,
- GetScreenState.CREDENTIAL_SELECTION,
- providerList.first()
- )
- }
-
- fun createPasskeyInitialUiState(): CreatePasskeyUiState {
- val providerList = createCredentialProviderList()
- return CreatePasskeyUiState(
- providers = providerList,
- currentScreenState = CreateScreenState.PASSKEY_INTRO,
- )
- }
-
- companion object {
- lateinit var repo: CredentialManagerRepo
-
- fun setup(
- context: Context,
- intent: Intent,
- ) {
- repo = CredentialManagerRepo(context, intent)
- }
-
- fun getInstance(): CredentialManagerRepo {
- return repo
- }
- }
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 98c824c..b538ae7 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -1,5 +1,22 @@
+/*
+ * 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.credentialmanager
+import android.credentials.ui.RequestInfo
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
@@ -16,14 +33,20 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
CredentialManagerRepo.setup(this, intent)
- val startDestination = intent.extras?.getString(
- "start_destination",
- "CREATE_PASSKEY"
- ) ?: "CREATE_PASSKEY"
-
- setContent {
- CredentialSelectorTheme {
- CredentialManagerBottomSheet(startDestination)
+ val requestInfo = intent.extras?.getParcelable<RequestInfo>(RequestInfo.EXTRA_REQUEST_INFO)
+ if (requestInfo != null) {
+ val requestType = requestInfo.type
+ setContent {
+ CredentialSelectorTheme {
+ CredentialManagerBottomSheet(requestType)
+ }
+ }
+ } else {
+ // TODO: prototype only code to be removed. In production should exit.
+ setContent {
+ CredentialSelectorTheme {
+ CredentialManagerBottomSheet(RequestInfo.TYPE_CREATE)
+ }
}
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
new file mode 100644
index 0000000..7159ab9
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -0,0 +1,106 @@
+/*
+ * 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.credentialmanager
+
+import android.content.Context
+import android.credentials.ui.Entry
+import android.credentials.ui.ProviderData
+import com.android.credentialmanager.createflow.CreateOptionInfo
+import com.android.credentialmanager.getflow.CredentialOptionInfo
+import com.android.credentialmanager.getflow.ProviderInfo
+
+/** Utility functions for converting CredentialManager data structures to or from UI formats. */
+class GetFlowUtils {
+ companion object {
+
+ fun toProviderList(
+ providerDataList: List<ProviderData>,
+ context: Context,
+ ): List<ProviderInfo> {
+ return providerDataList.map {
+ ProviderInfo(
+ // TODO: replace to extract from the service data structure when available
+ icon = context.getDrawable(R.drawable.ic_passkey)!!,
+ name = it.packageName,
+ appDomainName = "tribank.us",
+ credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
+ credentialOptions = toCredentialOptionInfoList(it.credentialEntries, context)
+ )
+ }
+ }
+
+
+ /* From service data structure to UI credential entry list representation. */
+ private fun toCredentialOptionInfoList(
+ credentialEntries: List<Entry>,
+ context: Context,
+ ): List<CredentialOptionInfo> {
+ return credentialEntries.map {
+ val credentialEntryUi = CredentialEntryUi.fromSlice(it.slice)
+
+ // Consider directly move the UI object into the class.
+ return@map CredentialOptionInfo(
+ // TODO: remove fallbacks
+ icon = credentialEntryUi.icon?.loadDrawable(context)
+ ?: context.getDrawable(R.drawable.ic_passkey)!!,
+ title = credentialEntryUi.userName.toString(),
+ subtitle = credentialEntryUi.displayName?.toString() ?: "Unknown display name",
+ id = it.entryId,
+ )
+ }
+ }
+ }
+}
+
+class CreateFlowUtils {
+ companion object {
+
+ fun toProviderList(
+ providerDataList: List<ProviderData>,
+ context: Context,
+ ): List<com.android.credentialmanager.createflow.ProviderInfo> {
+ return providerDataList.map {
+ com.android.credentialmanager.createflow.ProviderInfo(
+ // TODO: replace to extract from the service data structure when available
+ icon = context.getDrawable(R.drawable.ic_passkey)!!,
+ name = it.packageName,
+ appDomainName = "tribank.us",
+ credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
+ createOptions = toCreationOptionInfoList(it.credentialEntries, context),
+ )
+ }
+ }
+
+ private fun toCreationOptionInfoList(
+ creationEntries: List<Entry>,
+ context: Context,
+ ): List<CreateOptionInfo> {
+ return creationEntries.map {
+ val saveEntryUi = SaveEntryUi.fromSlice(it.slice)
+
+ return@map CreateOptionInfo(
+ // TODO: remove fallbacks
+ icon = saveEntryUi.icon?.loadDrawable(context)
+ ?: context.getDrawable(R.drawable.ic_passkey)!!,
+ title = saveEntryUi.title.toString(),
+ subtitle = saveEntryUi.subTitle?.toString() ?: "Unknown subtitle",
+ id = it.entryId,
+ )
+ }
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/SaveEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/SaveEntryUi.kt
new file mode 100644
index 0000000..2b63e1d
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/SaveEntryUi.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager
+
+import android.app.slice.Slice
+import android.credentials.ui.Entry
+import android.graphics.drawable.Icon
+
+/**
+ * UI representation for a save entry used during the create credential flow.
+ *
+ * TODO: move to jetpack.
+ */
+class SaveEntryUi(
+ val title: CharSequence,
+ val subTitle: CharSequence?,
+ val icon: Icon?,
+ // TODO: add
+) {
+ companion object {
+ fun fromSlice(slice: Slice): SaveEntryUi {
+ val items = slice.items
+
+ var title: String? = null
+ var subTitle: String? = null
+ var icon: Icon? = null
+
+ items.forEach {
+ if (it.hasHint(Entry.HINT_ICON)) {
+ icon = it.icon
+ } else if (it.hasHint(Entry.HINT_SUBTITLE)) {
+ subTitle = it.text.toString()
+ } else if (it.hasHint(Entry.HINT_TITLE)) {
+ title = it.text.toString()
+ }
+ }
+ // TODO: fail NPE more elegantly.
+ return SaveEntryUi(title!!, subTitle, icon)
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
index 8bb80a1..b5e9fd00 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
@@ -1,5 +1,23 @@
+/*
+ * 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.credentialmanager.common
+import android.credentials.ui.RequestInfo
+
enum class DialogType {
CREATE_PASSKEY,
GET_CREDENTIALS,
@@ -8,10 +26,10 @@
companion object {
fun toDialogType(value: String): DialogType {
- return try {
- valueOf(value)
- } catch (e: IllegalArgumentException) {
- UNKNOWN
+ return when (value) {
+ RequestInfo.TYPE_GET -> GET_CREDENTIALS
+ RequestInfo.TYPE_CREATE -> CREATE_PASSKEY
+ else -> UNKNOWN
}
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 044688b..12f1846 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.credentialmanager.createflow
import android.graphics.drawable.Drawable
@@ -14,7 +30,7 @@
val icon: Drawable,
val title: String,
val subtitle: String,
- val id: String,
+ val id: Int,
)
/** The name of the current screen. */
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
index 997519d..b61f465 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
@@ -222,7 +222,9 @@
) {
Column() {
TopAppBar(
- title = { Text(text = stringResource(R.string.string_more_options), style = Typography.subtitle1) },
+ title = {
+ Text(text = stringResource(R.string.string_more_options), style = Typography.subtitle1)
+ },
backgroundColor = lightBackgroundColor,
elevation = 0.dp,
navigationIcon =
@@ -343,7 +345,7 @@
@Composable
fun CreationSelectionCard(
providerInfo: ProviderInfo,
- onOptionSelected: (String) -> Unit,
+ onOptionSelected: (Int) -> Unit,
onCancel: () -> Unit,
multiProvider: Boolean,
onMoreOptionSelected: (String) -> Unit,
@@ -414,7 +416,7 @@
@ExperimentalMaterialApi
@Composable
-fun CreateOptionRow(createOptionInfo: CreateOptionInfo, onOptionSelected: (String) -> Unit) {
+fun CreateOptionRow(createOptionInfo: CreateOptionInfo, onOptionSelected: (Int) -> Unit) {
Chip(
modifier = Modifier.fillMaxWidth(),
onClick = {onOptionSelected(createOptionInfo.id)},
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt
index 15300de..5b70f9d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.credentialmanager.createflow
import android.util.Log
@@ -42,7 +58,7 @@
)
}
- fun onCreateOptionSelected(createOptionId: String) {
+ fun onCreateOptionSelected(createOptionId: Int) {
Log.d("Account Selector", "Option selected for creation: $createOptionId")
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 1ca70ed..0b18822 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.credentialmanager.getflow
import androidx.compose.foundation.Image
@@ -74,7 +90,7 @@
@Composable
fun CredentialSelectionCard(
providerInfo: ProviderInfo,
- onOptionSelected: (String) -> Unit,
+ onOptionSelected: (Int) -> Unit,
onCancel: () -> Unit,
multiProvider: Boolean,
onMoreOptionSelected: () -> Unit,
@@ -149,7 +165,7 @@
@Composable
fun CredentialOptionRow(
credentialOptionInfo: CredentialOptionInfo,
- onOptionSelected: (String) -> Unit
+ onOptionSelected: (Int) -> Unit
) {
Chip(
modifier = Modifier.fillMaxWidth(),
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
index 06bcd7f..0fdd8ec 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.credentialmanager.getflow
import android.util.Log
@@ -20,7 +36,7 @@
var uiState by mutableStateOf(credManRepo.getCredentialInitialUiState())
private set
- fun onCredentailSelected(credentialId: String) {
+ fun onCredentailSelected(credentialId: Int) {
Log.d("Account Selector", "credential selected: $credentialId")
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index 867e9c2..acea8c9 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.credentialmanager.getflow
import android.graphics.drawable.Drawable
@@ -14,7 +30,7 @@
val icon: Drawable,
val title: String,
val subtitle: String,
- val id: String,
+ val id: Int,
)
/** The name of the current screen. */
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
index 3885025..f762f6e 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
@@ -17,6 +17,9 @@
package com.android.settingslib.spa.framework.common
import android.app.Activity
+import android.util.Log
+
+private const val TAG = "SpaEnvironment"
object SpaEnvironmentFactory {
private var spaEnvironment: SpaEnvironment? = null
@@ -28,8 +31,10 @@
return spaEnvironment!!
}
set(env: SpaEnvironment) {
- if (spaEnvironment != null)
- throw UnsupportedOperationException("Spa environment is already set")
+ if (spaEnvironment != null) {
+ Log.w(TAG, "Spa environment is already set, ignore the latter one.")
+ return
+ }
spaEnvironment = env
}
}
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index c5bea2e..79677eea 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -4,6 +4,7 @@
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application android:allowClearUserData="false"
android:label="@string/app_label"
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 8efec67..3a25d85 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -86,6 +86,7 @@
import android.os.RemoteException;
import android.os.SELinux;
import android.os.ServiceManager;
+import android.os.SystemConfigManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -110,12 +111,11 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.FrameworkStatsLog;
import com.android.providers.settings.SettingsState.Setting;
-import com.android.server.SystemConfig;
-
-import com.google.android.collect.Sets;
import libcore.util.HexEncoding;
+import com.google.android.collect.Sets;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
@@ -368,6 +368,8 @@
// We have to call in the package manager with no lock held,
private volatile IPackageManager mPackageManager;
+ private volatile SystemConfigManager mSysConfigManager;
+
@GuardedBy("mLock")
private boolean mSyncConfigDisabledUntilReboot;
@@ -397,6 +399,7 @@
synchronized (mLock) {
mUserManager = UserManager.get(getContext());
mPackageManager = AppGlobals.getPackageManager();
+ mSysConfigManager = getContext().getSystemService(SystemConfigManager.class);
mHandlerThread = new HandlerThread(LOG_TAG,
Process.THREAD_PRIORITY_BACKGROUND);
mHandlerThread.start();
@@ -3875,8 +3878,7 @@
Setting currentSetting = secureSettings.getSettingLocked(
Settings.Secure.ENABLED_VR_LISTENERS);
if (currentSetting.isNull()) {
- ArraySet<ComponentName> l =
- SystemConfig.getInstance().getDefaultVrComponents();
+ List<ComponentName> l = mSysConfigManager.getDefaultVrComponents();
if (l != null && !l.isEmpty()) {
StringBuilder b = new StringBuilder();
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index d90156d..8135aaa 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -241,4 +241,6 @@
<string name="clock_title_bubble">Bubble</string>
<!-- Name of the "Analog" clock face [CHAR LIMIT=15]-->
<string name="clock_title_analog">Analog</string>
+ <!-- Title of bouncer when we want to authenticate before continuing with action. [CHAR LIMIT=NONE] -->
+ <string name="keyguard_unlock_to_continue">Unlock your device to continue</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index c34db15..93ee151 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -67,7 +67,6 @@
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
import android.view.WindowManager;
-import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@@ -318,7 +317,8 @@
}
void initMode(@Mode int mode, GlobalSettings globalSettings, FalsingManager falsingManager,
- UserSwitcherController userSwitcherController) {
+ UserSwitcherController userSwitcherController,
+ UserSwitcherViewMode.UserSwitcherCallback userSwitcherCallback) {
if (mCurrentMode == mode) return;
Log.i(TAG, "Switching mode from " + modeToString(mCurrentMode) + " to "
+ modeToString(mode));
@@ -330,7 +330,7 @@
mViewMode = new OneHandedViewMode();
break;
case MODE_USER_SWITCHER:
- mViewMode = new UserSwitcherViewMode();
+ mViewMode = new UserSwitcherViewMode(userSwitcherCallback);
break;
default:
mViewMode = new DefaultViewMode();
@@ -864,6 +864,12 @@
private UserSwitcherController.UserSwitchCallback mUserSwitchCallback =
this::setupUserSwitcher;
+ private UserSwitcherCallback mUserSwitcherCallback;
+
+ UserSwitcherViewMode(UserSwitcherCallback userSwitcherCallback) {
+ mUserSwitcherCallback = userSwitcherCallback;
+ }
+
@Override
public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
@NonNull KeyguardSecurityViewFlipper viewFlipper,
@@ -1040,34 +1046,25 @@
}
};
- if (adapter.getCount() < 2) {
- // The drop down arrow is at index 1
- ((LayerDrawable) mUserSwitcher.getBackground()).getDrawable(1).setAlpha(0);
- anchor.setClickable(false);
- return;
- } else {
- ((LayerDrawable) mUserSwitcher.getBackground()).getDrawable(1).setAlpha(255);
- }
-
anchor.setOnClickListener((v) -> {
if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
mPopup = new KeyguardUserSwitcherPopupMenu(v.getContext(), mFalsingManager);
mPopup.setAnchorView(anchor);
mPopup.setAdapter(adapter);
- mPopup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- public void onItemClick(AdapterView parent, View view, int pos, long id) {
- if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
- if (!view.isEnabled()) return;
-
- // Subtract one for the header
- UserRecord user = adapter.getItem(pos - 1);
- if (!user.isCurrent) {
- adapter.onUserListItemClicked(user);
- }
- mPopup.dismiss();
- mPopup = null;
- }
- });
+ mPopup.setOnItemClickListener((parent, view, pos, id) -> {
+ if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
+ if (!view.isEnabled()) return;
+ // Subtract one for the header
+ UserRecord user = adapter.getItem(pos - 1);
+ if (user.isManageUsers || user.isAddSupervisedUser) {
+ mUserSwitcherCallback.showUnlockToContinueMessage();
+ }
+ if (!user.isCurrent) {
+ adapter.onUserListItemClicked(user);
+ }
+ mPopup.dismiss();
+ mPopup = null;
+ });
mPopup.show();
});
}
@@ -1122,6 +1119,10 @@
constraintSet.applyTo(mView);
}
}
+
+ interface UserSwitcherCallback {
+ void showUnlockToContinueMessage();
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index d448f40..bcd1a1e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -620,7 +620,9 @@
mode = KeyguardSecurityContainer.MODE_ONE_HANDED;
}
- mView.initMode(mode, mGlobalSettings, mFalsingManager, mUserSwitcherController);
+ mView.initMode(mode, mGlobalSettings, mFalsingManager, mUserSwitcherController,
+ () -> showMessage(getContext().getString(R.string.keyguard_unlock_to_continue),
+ null));
}
public void reportFailedUnlockAttempt(int userId, int timeoutMs) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
index 9eb2c11..c9128e5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
@@ -109,12 +109,13 @@
object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
runningSecurityShiftAnimator = null
+ if (shouldRestoreLayerType) {
+ v.setLayerType(View.LAYER_TYPE_NONE, /* paint= */ null)
+ }
}
}
)
- var finishedFadingOutNonSecurityView = false
-
runningSecurityShiftAnimator.addUpdateListener { animation: ValueAnimator ->
val switchPoint = SECURITY_SHIFT_ANIMATION_FADE_OUT_PROPORTION
val isFadingOut = animation.animatedFraction < switchPoint
@@ -153,6 +154,13 @@
startRect.right + currentTranslation,
startRect.bottom
)
+ } else {
+ v.setLeftTopRightBottom(
+ startRect.left,
+ startRect.top,
+ startRect.right,
+ startRect.bottom
+ )
}
} else {
// And in again over the remaining (100-X)%.
@@ -175,32 +183,13 @@
endRect.right - translationRemaining,
endRect.bottom
)
- }
- }
- if (animation.animatedFraction == 1.0f && shouldRestoreLayerType) {
- v.setLayerType(View.LAYER_TYPE_NONE, /* paint= */ null)
- }
-
- // For views that are not the security view flipper, we do not want to apply
- // an x translation animation. Instead, we want to fade out, move to final position and
- // then fade in.
- if (v !is KeyguardSecurityViewFlipper) {
- // Opacity goes close to 0 but does not fully get to 0.
- if (opacity - 0.001f < 0f) {
+ } else {
v.setLeftTopRightBottom(
endRect.left,
endRect.top,
endRect.right,
endRect.bottom
)
- finishedFadingOutNonSecurityView = true
- } else if (!finishedFadingOutNonSecurityView) {
- v.setLeftTopRightBottom(
- startRect.left,
- startRect.top,
- startRect.right,
- startRect.bottom
- )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 8f6c96a..7f08f86 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -105,10 +105,6 @@
*/
public static final UnreleasedFlag MODERN_BOUNCER = new UnreleasedFlag(208);
- /** Whether UserSwitcherActivity should use modern architecture. */
- public static final ReleasedFlag MODERN_USER_SWITCHER_ACTIVITY =
- new ReleasedFlag(209, true);
-
/**
* Whether the user interactor and repository should use `UserSwitcherController`.
*
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 01cd3e2..f663b0d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -19,7 +19,7 @@
import android.content.Intent
import com.android.internal.widget.LockPatternUtils
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
@@ -67,19 +67,19 @@
*
* @param configKey The configuration key corresponding to the [KeyguardQuickAffordanceModel] of
* the affordance that was clicked
- * @param animationController An optional controller for the activity-launch animation
+ * @param expandable An optional [Expandable] for the activity- or dialog-launch animation
*/
fun onQuickAffordanceClicked(
configKey: KClass<out KeyguardQuickAffordanceConfig>,
- animationController: ActivityLaunchAnimator.Controller?,
+ expandable: Expandable?,
) {
@Suppress("UNCHECKED_CAST") val config = registry.get(configKey as KClass<Nothing>)
- when (val result = config.onQuickAffordanceClicked(animationController)) {
+ when (val result = config.onQuickAffordanceClicked(expandable)) {
is KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity ->
launchQuickAffordance(
intent = result.intent,
canShowWhileLocked = result.canShowWhileLocked,
- animationController = animationController
+ expandable = expandable,
)
is KeyguardQuickAffordanceConfig.OnClickedResult.Handled -> Unit
}
@@ -104,6 +104,7 @@
KeyguardQuickAffordanceModel.Visible(
configKey = configs[index]::class,
icon = visibleState.icon,
+ toggle = visibleState.toggle,
)
} else {
KeyguardQuickAffordanceModel.Hidden
@@ -114,7 +115,7 @@
private fun launchQuickAffordance(
intent: Intent,
canShowWhileLocked: Boolean,
- animationController: ActivityLaunchAnimator.Controller?,
+ expandable: Expandable?,
) {
@LockPatternUtils.StrongAuthTracker.StrongAuthFlags
val strongAuthFlags =
@@ -130,13 +131,13 @@
activityStarter.postStartActivityDismissingKeyguard(
intent,
0 /* delay */,
- animationController
+ expandable?.activityLaunchController(),
)
} else {
activityStarter.startActivity(
intent,
true /* dismissShade */,
- animationController,
+ expandable?.activityLaunchController(),
true /* showOverLockscreenWhenLocked */,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
index eb6bb92..e56b259 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
@@ -19,6 +19,7 @@
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
import kotlin.reflect.KClass
/**
@@ -35,5 +36,7 @@
val configKey: KClass<out KeyguardQuickAffordanceConfig>,
/** An icon for the affordance. */
val icon: Icon,
+ /** The toggle state for the affordance. */
+ val toggle: KeyguardQuickAffordanceToggleState,
) : KeyguardQuickAffordanceModel()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index 89604f0..8384260 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -20,7 +20,7 @@
import android.content.Context
import android.content.Intent
import androidx.annotation.DrawableRes
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.ContentDescription
@@ -61,7 +61,7 @@
}
override fun onQuickAffordanceClicked(
- animationController: ActivityLaunchAnimator.Controller?,
+ expandable: Expandable?,
): KeyguardQuickAffordanceConfig.OnClickedResult {
return KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity(
intent =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
index 8e1c6b7..95027d0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
@@ -18,8 +18,9 @@
package com.android.systemui.keyguard.domain.quickaffordance
import android.content.Intent
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
import kotlinx.coroutines.flow.Flow
/** Defines interface that can act as data source for a single quick affordance model. */
@@ -27,9 +28,7 @@
val state: Flow<State>
- fun onQuickAffordanceClicked(
- animationController: ActivityLaunchAnimator.Controller?
- ): OnClickedResult
+ fun onQuickAffordanceClicked(expandable: Expandable?): OnClickedResult
/**
* Encapsulates the state of a "quick affordance" in the keyguard bottom area (for example, a
@@ -44,6 +43,9 @@
data class Visible(
/** An icon for the affordance. */
val icon: Icon,
+ /** The toggle state for the affordance. */
+ val toggle: KeyguardQuickAffordanceToggleState =
+ KeyguardQuickAffordanceToggleState.NotSupported,
) : State()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
index d97deaf..502a607 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
@@ -18,7 +18,7 @@
package com.android.systemui.keyguard.domain.quickaffordance
import com.android.systemui.R
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.ContentDescription
@@ -66,7 +66,7 @@
}
override fun onQuickAffordanceClicked(
- animationController: ActivityLaunchAnimator.Controller?,
+ expandable: Expandable?,
): KeyguardQuickAffordanceConfig.OnClickedResult {
return KeyguardQuickAffordanceConfig.OnClickedResult.StartActivity(
intent = controller.intent,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 9196b09..a24a0d6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -23,7 +23,7 @@
import android.service.quickaccesswallet.QuickAccessWalletClient
import android.util.Log
import com.android.systemui.R
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.ContentDescription
@@ -84,11 +84,11 @@
}
override fun onQuickAffordanceClicked(
- animationController: ActivityLaunchAnimator.Controller?,
+ expandable: Expandable?,
): KeyguardQuickAffordanceConfig.OnClickedResult {
walletController.startQuickAccessUiIntent(
activityStarter,
- animationController,
+ expandable?.activityLaunchController(),
/* hasCard= */ true,
)
return KeyguardQuickAffordanceConfig.OnClickedResult.Handled
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordanceToggleState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordanceToggleState.kt
new file mode 100644
index 0000000..55d38a4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordanceToggleState.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.keyguard.shared.quickaffordance
+
+/** Enumerates all possible toggle states for a quick affordance on the lock-screen. */
+sealed class KeyguardQuickAffordanceToggleState {
+ /** Toggling is not supported. */
+ object NotSupported : KeyguardQuickAffordanceToggleState()
+ /** The quick affordance is on. */
+ object On : KeyguardQuickAffordanceToggleState()
+ /** The quick affordance is off. */
+ object Off : KeyguardQuickAffordanceToggleState()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index 65b85c0..2c99ca5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -29,7 +29,7 @@
import androidx.lifecycle.repeatOnLifecycle
import com.android.settingslib.Utils
import com.android.systemui.R
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.animation.Interpolators
import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
@@ -238,14 +238,26 @@
IconViewBinder.bind(viewModel.icon, view)
+ view.isActivated = viewModel.isActivated
view.drawable.setTint(
Utils.getColorAttrDefaultColor(
view.context,
- com.android.internal.R.attr.textColorPrimary
+ if (viewModel.isActivated) {
+ com.android.internal.R.attr.textColorPrimaryInverse
+ } else {
+ com.android.internal.R.attr.textColorPrimary
+ },
)
)
view.backgroundTintList =
- Utils.getColorAttr(view.context, com.android.internal.R.attr.colorSurface)
+ Utils.getColorAttr(
+ view.context,
+ if (viewModel.isActivated) {
+ com.android.internal.R.attr.colorAccentPrimary
+ } else {
+ com.android.internal.R.attr.colorSurface
+ }
+ )
view.isClickable = viewModel.isClickable
if (viewModel.isClickable) {
@@ -268,7 +280,7 @@
viewModel.onClicked(
KeyguardQuickAffordanceViewModel.OnClickedParameters(
configKey = viewModel.configKey,
- animationController = ActivityLaunchAnimator.Controller.fromView(view),
+ expandable = Expandable.fromView(view),
)
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
index 970ee4c..535ca72 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
@@ -23,6 +23,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
+import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -119,10 +120,11 @@
onClicked = { parameters ->
quickAffordanceInteractor.onQuickAffordanceClicked(
configKey = parameters.configKey,
- animationController = parameters.animationController,
+ expandable = parameters.expandable,
)
},
isClickable = isClickable,
+ isActivated = toggle is KeyguardQuickAffordanceToggleState.On,
)
is KeyguardQuickAffordanceModel.Hidden -> KeyguardQuickAffordanceViewModel()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
index 0971f13..bf598ba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
@@ -16,7 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
import kotlin.reflect.KClass
@@ -30,9 +30,10 @@
val icon: Icon = Icon.Resource(res = 0, contentDescription = null),
val onClicked: (OnClickedParameters) -> Unit = {},
val isClickable: Boolean = false,
+ val isActivated: Boolean = false,
) {
data class OnClickedParameters(
val configKey: KClass<out KeyguardQuickAffordanceConfig>,
- val animationController: ActivityLaunchAnimator.Controller?,
+ val expandable: Expandable?,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 50a10bc..6da8c69 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -114,6 +114,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope;
import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener;
@@ -211,6 +212,7 @@
private final NotificationShadeDepthController mNotificationShadeDepthController;
private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener;
private final UserContextProvider mUserContextProvider;
+ private final WakefulnessLifecycle mWakefulnessLifecycle;
private final RegionSamplingHelper mRegionSamplingHelper;
private final int mNavColorSampleMargin;
private NavigationBarFrame mFrame;
@@ -451,6 +453,28 @@
}
};
+ private final WakefulnessLifecycle.Observer mWakefulnessObserver =
+ new WakefulnessLifecycle.Observer() {
+ private void notifyScreenStateChanged(boolean isScreenOn) {
+ notifyNavigationBarScreenOn();
+ mView.onScreenStateChanged(isScreenOn);
+ }
+
+ @Override
+ public void onStartedWakingUp() {
+ notifyScreenStateChanged(true);
+ if (isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode)) {
+ mRegionSamplingHelper.start(mSamplingBounds);
+ }
+ }
+
+ @Override
+ public void onFinishedGoingToSleep() {
+ notifyScreenStateChanged(false);
+ mRegionSamplingHelper.stop();
+ }
+ };
+
@Inject
NavigationBar(
NavigationBarView navigationBarView,
@@ -491,7 +515,8 @@
NavigationBarTransitions navigationBarTransitions,
EdgeBackGestureHandler edgeBackGestureHandler,
Optional<BackAnimation> backAnimation,
- UserContextProvider userContextProvider) {
+ UserContextProvider userContextProvider,
+ WakefulnessLifecycle wakefulnessLifecycle) {
super(navigationBarView);
mFrame = navigationBarFrame;
mContext = context;
@@ -529,6 +554,7 @@
mTelecomManagerOptional = telecomManagerOptional;
mInputMethodManager = inputMethodManager;
mUserContextProvider = userContextProvider;
+ mWakefulnessLifecycle = wakefulnessLifecycle;
mNavColorSampleMargin = getResources()
.getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin);
@@ -682,11 +708,10 @@
prepareNavigationBarView();
checkNavBarModes();
- IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
- filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.addAction(Intent.ACTION_USER_SWITCHED);
+ IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter,
Handler.getMain(), UserHandle.ALL);
+ mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
notifyNavigationBarScreenOn();
mOverviewProxyService.addCallback(mOverviewProxyListener);
@@ -737,6 +762,7 @@
getBarTransitions().destroy();
mOverviewProxyService.removeCallback(mOverviewProxyListener);
mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
+ mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
if (mOrientationHandle != null) {
resetSecondaryHandle();
getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener);
@@ -1619,19 +1645,6 @@
return;
}
String action = intent.getAction();
- if (Intent.ACTION_SCREEN_OFF.equals(action)
- || Intent.ACTION_SCREEN_ON.equals(action)) {
- notifyNavigationBarScreenOn();
- boolean isScreenOn = Intent.ACTION_SCREEN_ON.equals(action);
- mView.onScreenStateChanged(isScreenOn);
- if (isScreenOn) {
- if (isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode)) {
- mRegionSamplingHelper.start(mSamplingBounds);
- }
- } else {
- mRegionSamplingHelper.stop();
- }
- }
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
// The accessibility settings may be different for the new user
updateAccessibilityStateFlags();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 029cf68..3fd1aa7 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -21,6 +21,7 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG;
import static com.android.systemui.shared.recents.utilities.Utilities.isTablet;
import android.content.ContentResolver;
@@ -141,7 +142,13 @@
public void onConfigChanged(Configuration newConfig) {
boolean isOldConfigTablet = mIsTablet;
mIsTablet = isTablet(mContext);
+ boolean willApplyConfig = mConfigChanges.applyNewConfig(mContext.getResources());
boolean largeScreenChanged = mIsTablet != isOldConfigTablet;
+ // TODO(b/243765256): Disable this logging once b/243765256 is fixed.
+ Log.d(DEBUG_MISSING_GESTURE_TAG, "NavbarController: newConfig=" + newConfig
+ + " mTaskbarDelegate initialized=" + mTaskbarDelegate.isInitialized()
+ + " willApplyConfigToNavbars=" + willApplyConfig
+ + " navBarCount=" + mNavigationBars.size());
if (mTaskbarDelegate.isInitialized()) {
mTaskbarDelegate.onConfigurationChanged(newConfig);
}
@@ -150,7 +157,7 @@
return;
}
- if (mConfigChanges.applyNewConfig(mContext.getResources())) {
+ if (willApplyConfig) {
for (int i = 0; i < mNavigationBars.size(); i++) {
recreateNavigationBar(mNavigationBars.keyAt(i));
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index a8799c7..709467f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -113,7 +113,7 @@
private static final int MAX_NUM_LOGGED_GESTURES = 10;
static final boolean DEBUG_MISSING_GESTURE = false;
- static final String DEBUG_MISSING_GESTURE_TAG = "NoBackGesture";
+ public static final String DEBUG_MISSING_GESTURE_TAG = "NoBackGesture";
private ISystemGestureExclusionListener mGestureExclusionListener =
new ISystemGestureExclusionListener.Stub() {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index fae0b50..1da866e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -46,6 +46,7 @@
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -78,6 +79,7 @@
private final PowerManager mPowerManager;
private final WarningsUI mWarnings;
+ private final WakefulnessLifecycle mWakefulnessLifecycle;
private InattentiveSleepWarningView mOverlayView;
private final Configuration mLastConfiguration = new Configuration();
private int mPlugType = 0;
@@ -107,11 +109,24 @@
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
+ private final WakefulnessLifecycle.Observer mWakefulnessObserver =
+ new WakefulnessLifecycle.Observer() {
+ @Override
+ public void onStartedWakingUp() {
+ mScreenOffTime = -1;
+ }
+
+ @Override
+ public void onFinishedGoingToSleep() {
+ mScreenOffTime = SystemClock.elapsedRealtime();
+ }
+ };
@Inject
public PowerUI(Context context, BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue, Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
WarningsUI warningsUI, EnhancedEstimates enhancedEstimates,
+ WakefulnessLifecycle wakefulnessLifecycle,
PowerManager powerManager) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
@@ -120,6 +135,7 @@
mWarnings = warningsUI;
mEnhancedEstimates = enhancedEstimates;
mPowerManager = powerManager;
+ mWakefulnessLifecycle = wakefulnessLifecycle;
}
public void start() {
@@ -138,6 +154,7 @@
false, obs, UserHandle.USER_ALL);
updateBatteryWarningLevels();
mReceiver.init();
+ mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
// Check to see if we need to let the user know that the phone previously shut down due
// to the temperature being too high.
@@ -233,8 +250,6 @@
IntentFilter filter = new IntentFilter();
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_USER_SWITCHED);
mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler);
// Force get initial values. Relying on Sticky behavior until API for getting info.
@@ -317,10 +332,6 @@
plugged, bucket);
});
- } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
- mScreenOffTime = SystemClock.elapsedRealtime();
- } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
- mScreenOffTime = -1;
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mWarnings.userSwitched();
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index 11d9555..d3c06f6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -23,7 +23,6 @@
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import com.android.settingslib.Utils
-import com.android.settingslib.drawable.UserIconDrawable
import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.ContentDescription
@@ -250,22 +249,19 @@
status: UserSwitcherStatusModel.Enabled
): FooterActionsButtonViewModel {
val icon = status.currentUserImage!!
- val iconTint =
- if (status.isGuestUser && icon !is UserIconDrawable) {
- Utils.getColorAttrDefaultColor(context, android.R.attr.colorForeground)
- } else {
- null
- }
return FooterActionsButtonViewModel(
id = R.id.multi_user_switch,
- Icon.Loaded(
- icon,
- ContentDescription.Loaded(userSwitcherContentDescription(status.currentUserName)),
- ),
- iconTint,
- R.drawable.qs_footer_action_circle,
- this::onUserSwitcherClicked,
+ icon =
+ Icon.Loaded(
+ icon,
+ ContentDescription.Loaded(
+ userSwitcherContentDescription(status.currentUserName)
+ ),
+ ),
+ iconTint = null,
+ background = R.drawable.qs_footer_action_circle,
+ onClick = this::onUserSwitcherClicked,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
index 950806d..ead3b7b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
@@ -49,7 +49,6 @@
private final SwipeDismissHandler mSwipeDismissHandler;
private final GestureDetector mSwipeDetector;
private View mActionsContainer;
- private View mActionsContainerBackground;
private SwipeDismissCallbacks mCallbacks;
private final DisplayMetrics mDisplayMetrics;
@@ -111,6 +110,9 @@
}
});
mSwipeDetector.setIsLongpressEnabled(false);
+
+ mCallbacks = new SwipeDismissCallbacks() {
+ }; // default to unimplemented callbacks
}
public void setCallbacks(SwipeDismissCallbacks callbacks) {
@@ -119,16 +121,13 @@
@Override
public boolean onInterceptHoverEvent(MotionEvent event) {
- if (mCallbacks != null) {
- mCallbacks.onInteraction();
- }
+ mCallbacks.onInteraction();
return super.onInterceptHoverEvent(event);
}
@Override // View
protected void onFinishInflate() {
mActionsContainer = findViewById(R.id.actions_container);
- mActionsContainerBackground = findViewById(R.id.actions_container_background);
}
@Override
@@ -186,6 +185,13 @@
inoutInfo.touchableRegion.set(r);
}
+ private int getBackgroundRight() {
+ // background expected to be null in testing.
+ // animation may have unexpected behavior if view is not present
+ View background = findViewById(R.id.actions_container_background);
+ return background == null ? 0 : background.getRight();
+ }
+
/**
* Allows a view to be swipe-dismissed, or returned to its location if distance threshold is not
* met
@@ -213,8 +219,6 @@
mGestureDetector = new GestureDetector(context, gestureListener);
mDisplayMetrics = new DisplayMetrics();
context.getDisplay().getRealMetrics(mDisplayMetrics);
- mCallbacks = new SwipeDismissCallbacks() {
- }; // default to unimplemented callbacks
}
@Override
@@ -230,7 +234,9 @@
return true;
}
if (isPastDismissThreshold()) {
- dismiss();
+ ValueAnimator anim = createSwipeDismissAnimation();
+ mCallbacks.onSwipeDismissInitiated(anim);
+ dismiss(anim);
} else {
// if we've moved, but not past the threshold, start the return animation
if (DEBUG_DISMISS) {
@@ -295,10 +301,7 @@
}
void dismiss() {
- float velocityPxPerMs = FloatingWindowUtil.dpToPx(mDisplayMetrics, VELOCITY_DP_PER_MS);
- ValueAnimator anim = createSwipeDismissAnimation(velocityPxPerMs);
- mCallbacks.onSwipeDismissInitiated(anim);
- dismiss(anim);
+ dismiss(createSwipeDismissAnimation());
}
private void dismiss(ValueAnimator animator) {
@@ -323,6 +326,11 @@
mDismissAnimation.start();
}
+ private ValueAnimator createSwipeDismissAnimation() {
+ float velocityPxPerMs = FloatingWindowUtil.dpToPx(mDisplayMetrics, VELOCITY_DP_PER_MS);
+ return createSwipeDismissAnimation(velocityPxPerMs);
+ }
+
private ValueAnimator createSwipeDismissAnimation(float velocity) {
// velocity is measured in pixels per millisecond
velocity = Math.min(3, Math.max(1, velocity));
@@ -337,7 +345,7 @@
if (startX > 0 || (startX == 0 && layoutDir == LAYOUT_DIRECTION_RTL)) {
finalX = mDisplayMetrics.widthPixels;
} else {
- finalX = -1 * mActionsContainerBackground.getRight();
+ finalX = -1 * getBackgroundRight();
}
float distance = Math.abs(finalX - startX);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 704e115..6d5121a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -28,6 +28,7 @@
import static com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW;
import static com.android.systemui.screenshot.LogConfig.logTag;
import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER;
+import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT;
import static java.util.Objects.requireNonNull;
@@ -331,9 +332,7 @@
if (DEBUG_UI) {
Log.d(TAG, "Corner timeout hit");
}
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT, 0,
- mPackageName);
- ScreenshotController.this.dismissScreenshot(false);
+ dismissScreenshot(SCREENSHOT_INTERACTION_TIMEOUT);
});
mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
@@ -361,8 +360,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (ClipboardOverlayController.COPY_OVERLAY_ACTION.equals(intent.getAction())) {
- mUiEventLogger.log(SCREENSHOT_DISMISSED_OTHER);
- dismissScreenshot(false);
+ dismissScreenshot(SCREENSHOT_DISMISSED_OTHER);
}
}
};
@@ -410,24 +408,20 @@
/**
* Clears current screenshot
*/
- void dismissScreenshot(boolean immediate) {
+ void dismissScreenshot(ScreenshotEvent event) {
if (DEBUG_DISMISS) {
- Log.d(TAG, "dismissScreenshot(immediate=" + immediate + ")");
+ Log.d(TAG, "dismissScreenshot");
}
// If we're already animating out, don't restart the animation
- // (but do obey an immediate dismissal)
- if (!immediate && mScreenshotView.isDismissing()) {
+ if (mScreenshotView.isDismissing()) {
if (DEBUG_DISMISS) {
Log.v(TAG, "Already dismissing, ignoring duplicate command");
}
return;
}
+ mUiEventLogger.log(event, 0, mPackageName);
mScreenshotHandler.cancelTimeout();
- if (immediate) {
- finishDismiss();
- } else {
- mScreenshotView.animateDismissal();
- }
+ mScreenshotView.animateDismissal();
}
boolean isPendingSharedTransition() {
@@ -500,7 +494,7 @@
if (DEBUG_INPUT) {
Log.d(TAG, "onKeyEvent: KeyEvent.KEYCODE_BACK");
}
- dismissScreenshot(false);
+ dismissScreenshot(SCREENSHOT_DISMISSED_OTHER);
return true;
}
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index a4a59ce..2176825 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -89,8 +89,7 @@
Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
}
if (!mScreenshot.isPendingSharedTransition()) {
- mUiEventLogger.log(SCREENSHOT_DISMISSED_OTHER);
- mScreenshot.dismissScreenshot(false);
+ mScreenshot.dismissScreenshot(SCREENSHOT_DISMISSED_OTHER);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index c290ce2..184dc25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -189,7 +189,6 @@
protected NotificationPresenter mPresenter;
protected ContentObserver mLockscreenSettingsObserver;
protected ContentObserver mSettingsObserver;
- private boolean mHideSilentNotificationsOnLockscreen;
@Inject
public NotificationLockscreenUserManagerImpl(Context context,
@@ -266,12 +265,6 @@
UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
- mSecureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
- true,
- mLockscreenSettingsObserver,
- UserHandle.USER_ALL);
-
- mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
mSettingsObserver);
@@ -340,9 +333,6 @@
final boolean allowedByDpm = (dpmFlags
& DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0;
- mHideSilentNotificationsOnLockscreen = mSecureSettings.getIntForUser(
- Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1, mCurrentUserId) == 0;
-
setShowLockscreenNotifications(show && allowedByDpm);
if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
index 6f41425..9a7610d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
@@ -114,7 +114,18 @@
*/
public void unbindHeadsUpView(NotificationEntry entry) {
abortBindCallback(entry);
- mStage.getStageParams(entry).markContentViewsFreeable(FLAG_CONTENT_VIEW_HEADS_UP);
+
+ // params may be null if the notification was already removed from the collection but we let
+ // it stick around during a launch animation. In this case, the heads up view has already
+ // been unbound, so we don't need to unbind it.
+ // TODO(b/253081345): Change this back to getStageParams and remove null check.
+ RowContentBindParams params = mStage.tryGetStageParams(entry);
+ if (params == null) {
+ mLogger.entryBindStageParamsNullOnUnbind(entry);
+ return;
+ }
+
+ params.markContentViewsFreeable(FLAG_CONTENT_VIEW_HEADS_UP);
mLogger.entryContentViewMarkedFreeable(entry);
mStage.requestRebind(entry, e -> mLogger.entryUnbound(e));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
index d1feaa0..5dbec8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
@@ -47,6 +47,14 @@
"start unbinding heads up entry $str1 "
})
}
+
+ fun entryBindStageParamsNullOnUnbind(entry: NotificationEntry) {
+ buffer.log(TAG, INFO, {
+ str1 = entry.logKey
+ }, {
+ "heads up entry bind stage params null on unbind $str1 "
+ })
+ }
}
private const val TAG = "HeadsUpViewBinder"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
index 7c41800..d626c18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BindStage.java
@@ -21,6 +21,7 @@
import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -64,7 +65,7 @@
* Get the stage parameters for the entry. Clients should use this to modify how the stage
* handles the notification content.
*/
- public final Params getStageParams(@NonNull NotificationEntry entry) {
+ public final @NonNull Params getStageParams(@NonNull NotificationEntry entry) {
Params params = mContentParams.get(entry);
if (params == null) {
// TODO: This should throw an exception but there are some cases of re-entrant calls
@@ -79,6 +80,17 @@
return params;
}
+ // TODO(b/253081345): Remove this method.
+ /**
+ * Get the stage parameters for the entry, or null if there are no stage parameters for the
+ * entry.
+ *
+ * @see #getStageParams(NotificationEntry)
+ */
+ public final @Nullable Params tryGetStageParams(@NonNull NotificationEntry entry) {
+ return mContentParams.get(entry);
+ }
+
/**
* Create a params entry for the notification for this stage.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
index 5b2d695..2f0ebf7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
@@ -35,8 +35,8 @@
protected val controller: UserSwitcherController,
) : BaseAdapter() {
- protected open val users: ArrayList<UserRecord>
- get() = controller.users
+ protected open val users: List<UserRecord>
+ get() = controller.users.filter { !controller.isKeyguardShowing || !it.isRestricted }
init {
controller.addAdapter(WeakReference(this))
@@ -112,6 +112,7 @@
item.isGuest,
item.isAddSupervisedUser,
isTablet,
+ item.isManageUsers,
)
return checkNotNull(context.getDrawable(iconRes))
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 494a4bb..c150654 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -53,6 +53,7 @@
import com.android.systemui.util.ViewController;
import java.util.ArrayList;
+import java.util.List;
import javax.inject.Inject;
@@ -456,7 +457,7 @@
}
void refreshUserOrder() {
- ArrayList<UserRecord> users = super.getUsers();
+ List<UserRecord> users = super.getUsers();
mUsersOrdered = new ArrayList<>(users.size());
for (int i = 0; i < users.size(); i++) {
UserRecord record = users.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt
index af39eee..935fc7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt
@@ -249,7 +249,7 @@
override fun startActivity(intent: Intent) {
if (useInteractor) {
- activityStarter.startActivity(intent, /* dismissShade= */ false)
+ activityStarter.startActivity(intent, /* dismissShade= */ true)
} else {
_oldImpl.startActivity(intent)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java
index 46d2f3a..c294c37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java
@@ -49,6 +49,7 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.LatencyTracker;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.users.UserCreatingDialog;
import com.android.systemui.GuestResetOrExitSessionReceiver;
import com.android.systemui.GuestResumeSessionReceiver;
@@ -399,6 +400,16 @@
records.add(userRecord);
}
+ if (canManageUsers()) {
+ records.add(LegacyUserDataHelper.createRecord(
+ mContext,
+ KeyguardUpdateMonitor.getCurrentUser(),
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+ /* isRestricted= */ false,
+ /* isSwitchToEnabled= */ true
+ ));
+ }
+
mUiExecutor.execute(() -> {
if (records != null) {
mUsers = records;
@@ -438,6 +449,14 @@
&& mUserManager.canAddMoreUsers(UserManager.USER_TYPE_FULL_SECONDARY);
}
+ @VisibleForTesting
+ boolean canManageUsers() {
+ UserInfo currentUser = mUserTracker.getUserInfo();
+ return mUserSwitcherEnabled
+ && ((currentUser != null && currentUser.isAdmin())
+ || mAddUsersFromLockScreen.getValue());
+ }
+
private boolean createIsRestricted() {
return !mAddUsersFromLockScreen.getValue();
}
@@ -525,6 +544,8 @@
showAddUserDialog(dialogShower);
} else if (record.isAddSupervisedUser) {
startSupervisedUserActivity();
+ } else if (record.isManageUsers) {
+ startActivity(new Intent(Settings.ACTION_USER_SETTINGS));
} else {
onUserListItemClicked(record.info.id, record, dialogShower);
}
@@ -984,7 +1005,7 @@
@Override
public void startActivity(Intent intent) {
- mActivityStarter.startActivity(intent, true);
+ mActivityStarter.startActivity(intent, /* dismissShade= */ true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index 108ab43..7f1195b 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -16,426 +16,41 @@
package com.android.systemui.user
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.graphics.drawable.BitmapDrawable
-import android.graphics.drawable.Drawable
-import android.graphics.drawable.GradientDrawable
-import android.graphics.drawable.LayerDrawable
import android.os.Bundle
-import android.os.UserManager
-import android.provider.Settings
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.MotionEvent
import android.view.View
-import android.view.ViewGroup
-import android.widget.AdapterView
-import android.widget.ArrayAdapter
-import android.widget.ImageView
-import android.widget.TextView
-import android.window.OnBackInvokedCallback
-import android.window.OnBackInvokedDispatcher
import androidx.activity.ComponentActivity
-import androidx.constraintlayout.helper.widget.Flow
import androidx.lifecycle.ViewModelProvider
-import com.android.internal.annotations.VisibleForTesting
-import com.android.internal.util.UserIcons
-import com.android.settingslib.Utils
-import com.android.systemui.Gefingerpoken
import com.android.systemui.R
-import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
-import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.policy.BaseUserSwitcherAdapter
-import com.android.systemui.statusbar.policy.UserSwitcherController
-import com.android.systemui.user.data.source.UserRecord
import com.android.systemui.user.ui.binder.UserSwitcherViewBinder
import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
import dagger.Lazy
import javax.inject.Inject
-import kotlin.math.ceil
-
-private const val USER_VIEW = "user_view"
/** Support a fullscreen user switcher */
open class UserSwitcherActivity
@Inject
constructor(
- private val userSwitcherController: UserSwitcherController,
- private val broadcastDispatcher: BroadcastDispatcher,
private val falsingCollector: FalsingCollector,
- private val falsingManager: FalsingManager,
- private val userManager: UserManager,
- private val userTracker: UserTracker,
- private val flags: FeatureFlags,
private val viewModelFactory: Lazy<UserSwitcherViewModel.Factory>,
) : ComponentActivity() {
- private lateinit var parent: UserSwitcherRootView
- private lateinit var broadcastReceiver: BroadcastReceiver
- private var popupMenu: UserSwitcherPopupMenu? = null
- private lateinit var addButton: View
- private var addUserRecords = mutableListOf<UserRecord>()
- private val onBackCallback = OnBackInvokedCallback { finish() }
- private val userSwitchedCallback: UserTracker.Callback =
- object : UserTracker.Callback {
- override fun onUserChanged(newUser: Int, userContext: Context) {
- finish()
- }
- }
- // When the add users options become available, insert another option to manage users
- private val manageUserRecord =
- UserRecord(
- null /* info */,
- null /* picture */,
- false /* isGuest */,
- false /* isCurrent */,
- false /* isAddUser */,
- false /* isRestricted */,
- false /* isSwitchToEnabled */,
- false /* isAddSupervisedUser */
- )
-
- private val adapter: UserAdapter by lazy { UserAdapter() }
-
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- createActivity()
- }
-
- @VisibleForTesting
- fun createActivity() {
setContentView(R.layout.user_switcher_fullscreen)
window.decorView.systemUiVisibility =
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
- if (isUsingModernArchitecture()) {
- Log.d(TAG, "Using modern architecture.")
- val viewModel =
- ViewModelProvider(this, viewModelFactory.get())[UserSwitcherViewModel::class.java]
- UserSwitcherViewBinder.bind(
- view = requireViewById(R.id.user_switcher_root),
- viewModel = viewModel,
- lifecycleOwner = this,
- layoutInflater = layoutInflater,
- falsingCollector = falsingCollector,
- onFinish = this::finish,
- )
- return
- } else {
- Log.d(TAG, "Not using modern architecture.")
- }
-
- parent = requireViewById<UserSwitcherRootView>(R.id.user_switcher_root)
-
- parent.touchHandler =
- object : Gefingerpoken {
- override fun onTouchEvent(ev: MotionEvent?): Boolean {
- falsingCollector.onTouchEvent(ev)
- return false
- }
- }
-
- requireViewById<View>(R.id.cancel).apply { setOnClickListener { _ -> finish() } }
-
- addButton =
- requireViewById<View>(R.id.add).apply { setOnClickListener { _ -> showPopupMenu() } }
-
- onBackInvokedDispatcher.registerOnBackInvokedCallback(
- OnBackInvokedDispatcher.PRIORITY_DEFAULT,
- onBackCallback
+ val viewModel =
+ ViewModelProvider(this, viewModelFactory.get())[UserSwitcherViewModel::class.java]
+ UserSwitcherViewBinder.bind(
+ view = requireViewById(R.id.user_switcher_root),
+ viewModel = viewModel,
+ lifecycleOwner = this,
+ layoutInflater = layoutInflater,
+ falsingCollector = falsingCollector,
+ onFinish = this::finish,
)
-
- userSwitcherController.init(parent)
- initBroadcastReceiver()
-
- parent.post { buildUserViews() }
- userTracker.addCallback(userSwitchedCallback, mainExecutor)
- }
-
- private fun showPopupMenu() {
- val items = mutableListOf<UserRecord>()
- addUserRecords.forEach { items.add(it) }
-
- var popupMenuAdapter =
- ItemAdapter(
- this,
- R.layout.user_switcher_fullscreen_popup_item,
- layoutInflater,
- { item: UserRecord -> adapter.getName(this@UserSwitcherActivity, item, true) },
- { item: UserRecord ->
- adapter.findUserIcon(item, true).mutate().apply {
- setTint(
- resources.getColor(
- R.color.user_switcher_fullscreen_popup_item_tint,
- getTheme()
- )
- )
- }
- }
- )
- popupMenuAdapter.addAll(items)
-
- popupMenu =
- UserSwitcherPopupMenu(this).apply {
- setAnchorView(addButton)
- setAdapter(popupMenuAdapter)
- setOnItemClickListener { parent: AdapterView<*>, view: View, pos: Int, id: Long ->
- if (falsingManager.isFalseTap(LOW_PENALTY) || !view.isEnabled()) {
- return@setOnItemClickListener
- }
- // -1 for the header
- val item = popupMenuAdapter.getItem(pos - 1)
- if (item == manageUserRecord) {
- val i = Intent().setAction(Settings.ACTION_USER_SETTINGS)
- this@UserSwitcherActivity.startActivity(i)
- } else {
- adapter.onUserListItemClicked(item)
- }
-
- dismiss()
- popupMenu = null
-
- if (!item.isAddUser) {
- this@UserSwitcherActivity.finish()
- }
- }
-
- show()
- }
- }
-
- private fun buildUserViews() {
- var count = 0
- var start = 0
- for (i in 0 until parent.getChildCount()) {
- if (parent.getChildAt(i).getTag() == USER_VIEW) {
- if (count == 0) start = i
- count++
- }
- }
- parent.removeViews(start, count)
- addUserRecords.clear()
- val flow = requireViewById<Flow>(R.id.flow)
- val totalWidth = parent.width
- val userViewCount = adapter.getTotalUserViews()
- val maxColumns = getMaxColumns(userViewCount)
- val horizontalGap =
- resources.getDimensionPixelSize(R.dimen.user_switcher_fullscreen_horizontal_gap)
- val totalWidthOfHorizontalGap = (maxColumns - 1) * horizontalGap
- val maxWidgetDiameter = (totalWidth - totalWidthOfHorizontalGap) / maxColumns
-
- flow.setMaxElementsWrap(maxColumns)
-
- for (i in 0 until adapter.getCount()) {
- val item = adapter.getItem(i)
- if (adapter.doNotRenderUserView(item)) {
- addUserRecords.add(item)
- } else {
- val userView = adapter.getView(i, null, parent)
- userView.requireViewById<ImageView>(R.id.user_switcher_icon).apply {
- val lp = layoutParams
- if (maxWidgetDiameter < lp.width) {
- lp.width = maxWidgetDiameter
- lp.height = maxWidgetDiameter
- layoutParams = lp
- }
- }
-
- userView.setId(View.generateViewId())
- parent.addView(userView)
-
- // Views must have an id and a parent in order for Flow to lay them out
- flow.addView(userView)
-
- userView.setOnClickListener { v ->
- if (falsingManager.isFalseTap(LOW_PENALTY) || !v.isEnabled()) {
- return@setOnClickListener
- }
-
- if (!item.isCurrent || item.isGuest) {
- adapter.onUserListItemClicked(item)
- }
- }
- }
- }
-
- if (!addUserRecords.isEmpty()) {
- addUserRecords.add(manageUserRecord)
- addButton.visibility = View.VISIBLE
- } else {
- addButton.visibility = View.GONE
- }
- }
-
- override fun onBackPressed() {
- if (isUsingModernArchitecture()) {
- return super.onBackPressed()
- }
-
- finish()
- }
-
- override fun onDestroy() {
- super.onDestroy()
- if (isUsingModernArchitecture()) {
- return
- }
- destroyActivity()
- }
-
- @VisibleForTesting
- fun destroyActivity() {
- onBackInvokedDispatcher.unregisterOnBackInvokedCallback(onBackCallback)
- broadcastDispatcher.unregisterReceiver(broadcastReceiver)
- userTracker.removeCallback(userSwitchedCallback)
- }
-
- private fun initBroadcastReceiver() {
- broadcastReceiver =
- object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- val action = intent.getAction()
- if (Intent.ACTION_SCREEN_OFF.equals(action)) {
- finish()
- }
- }
- }
-
- val filter = IntentFilter()
- filter.addAction(Intent.ACTION_SCREEN_OFF)
- broadcastDispatcher.registerReceiver(broadcastReceiver, filter)
- }
-
- @VisibleForTesting
- fun getMaxColumns(userCount: Int): Int {
- return if (userCount < 5) 4 else ceil(userCount / 2.0).toInt()
- }
-
- private fun isUsingModernArchitecture(): Boolean {
- return flags.isEnabled(Flags.MODERN_USER_SWITCHER_ACTIVITY)
- }
-
- /** Provides views to populate the option menu. */
- private class ItemAdapter(
- val parentContext: Context,
- val resource: Int,
- val layoutInflater: LayoutInflater,
- val textGetter: (UserRecord) -> String,
- val iconGetter: (UserRecord) -> Drawable
- ) : ArrayAdapter<UserRecord>(parentContext, resource) {
-
- override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- val item = getItem(position)
- val view = convertView ?: layoutInflater.inflate(resource, parent, false)
-
- view.requireViewById<ImageView>(R.id.icon).apply { setImageDrawable(iconGetter(item)) }
- view.requireViewById<TextView>(R.id.text).apply { setText(textGetter(item)) }
-
- return view
- }
- }
-
- private inner class UserAdapter : BaseUserSwitcherAdapter(userSwitcherController) {
- override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- val item = getItem(position)
- var view = convertView as ViewGroup?
- if (view == null) {
- view =
- layoutInflater.inflate(R.layout.user_switcher_fullscreen_item, parent, false)
- as ViewGroup
- }
- (view.getChildAt(0) as ImageView).apply { setImageDrawable(getDrawable(item)) }
- (view.getChildAt(1) as TextView).apply { setText(getName(getContext(), item)) }
-
- view.setEnabled(item.isSwitchToEnabled)
- UserSwitcherController.setSelectableAlpha(view)
- view.setTag(USER_VIEW)
- return view
- }
-
- override fun getName(context: Context, item: UserRecord, isTablet: Boolean): String {
- return if (item == manageUserRecord) {
- getString(R.string.manage_users)
- } else {
- super.getName(context, item, isTablet)
- }
- }
-
- fun findUserIcon(item: UserRecord, isTablet: Boolean = false): Drawable {
- if (item == manageUserRecord) {
- return getDrawable(R.drawable.ic_manage_users)
- }
- if (item.info == null) {
- return getIconDrawable(this@UserSwitcherActivity, item, isTablet)
- }
- val userIcon = userManager.getUserIcon(item.info.id)
- if (userIcon != null) {
- return BitmapDrawable(userIcon)
- }
- return UserIcons.getDefaultUserIcon(resources, item.info.id, false)
- }
-
- fun getTotalUserViews(): Int {
- return users.count { item -> !doNotRenderUserView(item) }
- }
-
- fun doNotRenderUserView(item: UserRecord): Boolean {
- return item.isAddUser || item.isAddSupervisedUser || item.isGuest && item.info == null
- }
-
- private fun getDrawable(item: UserRecord): Drawable {
- var drawable =
- if (item.isGuest) {
- getDrawable(R.drawable.ic_account_circle)
- } else {
- findUserIcon(item)
- }
- drawable.mutate()
-
- if (!item.isCurrent && !item.isSwitchToEnabled) {
- drawable.setTint(
- resources.getColor(
- R.color.kg_user_switcher_restricted_avatar_icon_color,
- getTheme()
- )
- )
- }
-
- val ld = getDrawable(R.drawable.user_switcher_icon_large).mutate() as LayerDrawable
- if (item == userSwitcherController.currentUserRecord) {
- (ld.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
- val stroke =
- resources.getDimensionPixelSize(R.dimen.user_switcher_icon_selected_width)
- val color =
- Utils.getColorAttrDefaultColor(
- this@UserSwitcherActivity,
- com.android.internal.R.attr.colorAccentPrimary
- )
-
- setStroke(stroke, color)
- }
- }
-
- ld.setDrawableByLayerId(R.id.user_avatar, drawable)
- return ld
- }
-
- override fun notifyDataSetChanged() {
- super.notifyDataSetChanged()
- buildUserViews()
- }
- }
-
- companion object {
- private const val TAG = "UserSwitcherActivity"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
index 9370286..d4fb563 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
@@ -47,6 +47,9 @@
* If not disabled, this is `null`.
*/
@JvmField val enforcedAdmin: RestrictedLockUtils.EnforcedAdmin? = null,
+
+ /** Whether this record is to go to the Settings page to manage users. */
+ @JvmField val isManageUsers: Boolean = false
) {
/** Returns a new instance of [UserRecord] with its [isCurrent] set to the given value. */
fun copyWithIsCurrent(isCurrent: Boolean): UserRecord {
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt
index 1b4746a..dc004f3 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt
@@ -82,6 +82,15 @@
)
}
+ fun canManageUsers(
+ repository: UserRepository,
+ isUserSwitcherEnabled: Boolean,
+ isAddUsersFromLockScreenEnabled: Boolean,
+ ): Boolean {
+ return isUserSwitcherEnabled &&
+ (repository.getSelectedUserInfo().isAdmin || isAddUsersFromLockScreenEnabled)
+ }
+
/**
* Returns `true` if the current user is allowed to add users to the device; `false` otherwise.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index 142a328..ba5a82a 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -102,6 +102,7 @@
interface UserCallback {
/** Returns `true` if this callback can be cleaned-up. */
fun isEvictable(): Boolean = false
+
/** Notifies that the state of users on the device has changed. */
fun onUserStateChanged()
}
@@ -164,10 +165,11 @@
get() =
if (isNewImpl) {
combine(
+ repository.selectedUserInfo,
repository.userInfos,
repository.userSwitcherSettings,
keyguardInteractor.isKeyguardShowing,
- ) { userInfos, settings, isDeviceLocked ->
+ ) { _, userInfos, settings, isDeviceLocked ->
buildList {
val hasGuestUser = userInfos.any { it.isGuest }
if (
@@ -183,35 +185,45 @@
add(UserActionModel.ENTER_GUEST_MODE)
}
- if (isDeviceLocked && !settings.isAddUsersFromLockscreen) {
+ if (!isDeviceLocked || settings.isAddUsersFromLockscreen) {
// The device is locked and our setting to allow actions that add users
// from the lock-screen is not enabled. The guest action from above is
// always allowed, even when the device is locked, but the various "add
// user" actions below are not. We can finish building the list here.
- return@buildList
+
+ val canCreateUsers =
+ UserActionsUtil.canCreateUser(
+ manager,
+ repository,
+ settings.isUserSwitcherEnabled,
+ settings.isAddUsersFromLockscreen,
+ )
+
+ if (canCreateUsers) {
+ add(UserActionModel.ADD_USER)
+ }
+
+ if (
+ UserActionsUtil.canCreateSupervisedUser(
+ manager,
+ repository,
+ settings.isUserSwitcherEnabled,
+ settings.isAddUsersFromLockscreen,
+ supervisedUserPackageName,
+ )
+ ) {
+ add(UserActionModel.ADD_SUPERVISED_USER)
+ }
}
if (
- UserActionsUtil.canCreateUser(
- manager,
+ UserActionsUtil.canManageUsers(
repository,
settings.isUserSwitcherEnabled,
settings.isAddUsersFromLockscreen,
)
) {
- add(UserActionModel.ADD_USER)
- }
-
- if (
- UserActionsUtil.canCreateSupervisedUser(
- manager,
- repository,
- settings.isUserSwitcherEnabled,
- settings.isAddUsersFromLockscreen,
- supervisedUserPackageName,
- )
- ) {
- add(UserActionModel.ADD_SUPERVISED_USER)
+ add(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
}
}
}
@@ -264,7 +276,10 @@
toRecord(
action = it,
selectedUserId = selectedUserInfo.id,
- isAddFromLockscreenEnabled = settings.isAddUsersFromLockscreen,
+ isRestricted =
+ it != UserActionModel.ENTER_GUEST_MODE &&
+ it != UserActionModel.NAVIGATE_TO_USER_MANAGEMENT &&
+ !settings.isAddUsersFromLockscreen,
)
}
)
@@ -482,12 +497,12 @@
.setAction(UserManager.ACTION_CREATE_SUPERVISED_USER)
.setPackage(supervisedUserPackageName)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
- /* dismissShade= */ false,
+ /* dismissShade= */ true,
)
UserActionModel.NAVIGATE_TO_USER_MANAGEMENT ->
activityStarter.startActivity(
Intent(Settings.ACTION_USER_SETTINGS),
- /* dismissShade= */ false,
+ /* dismissShade= */ true,
)
}
} else {
@@ -575,20 +590,13 @@
private suspend fun toRecord(
action: UserActionModel,
selectedUserId: Int,
- isAddFromLockscreenEnabled: Boolean,
+ isRestricted: Boolean,
): UserRecord {
return LegacyUserDataHelper.createRecord(
context = applicationContext,
selectedUserId = selectedUserId,
actionType = action,
- isRestricted =
- if (action == UserActionModel.ENTER_GUEST_MODE) {
- // Entering guest mode is never restricted, so it's allowed to happen from the
- // lockscreen even if the "add from lockscreen" system setting is off.
- false
- } else {
- !isAddFromLockscreenEnabled
- },
+ isRestricted = isRestricted,
isSwitchToEnabled =
canSwitchUsers(selectedUserId) &&
// If the user is auto-created is must not be currently resetting.
diff --git a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt
index 137de15..03a7470 100644
--- a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt
@@ -80,6 +80,7 @@
context = context,
selectedUserId = selectedUserId,
),
+ isManageUsers = actionType == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
)
}
@@ -90,6 +91,7 @@
record.isAddUser -> UserActionModel.ADD_USER
record.isAddSupervisedUser -> UserActionModel.ADD_SUPERVISED_USER
record.isGuest -> UserActionModel.ENTER_GUEST_MODE
+ record.isManageUsers -> UserActionModel.NAVIGATE_TO_USER_MANAGEMENT
else -> error("Not a known action: $record")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
index 15fdc35..e74232d 100644
--- a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
@@ -22,7 +22,6 @@
import androidx.annotation.StringRes
import com.android.systemui.R
import com.android.systemui.user.data.source.UserRecord
-import kotlin.math.ceil
/**
* Defines utility functions for helping with legacy UI code for users.
@@ -33,16 +32,6 @@
*/
object LegacyUserUiHelper {
- /** Returns the maximum number of columns for user items in the user switcher. */
- fun getMaxUserSwitcherItemColumns(userCount: Int): Int {
- // TODO(b/243844097): remove this once we remove the old user switcher implementation.
- return if (userCount < 5) {
- 4
- } else {
- ceil(userCount / 2.0).toInt()
- }
- }
-
@JvmStatic
@DrawableRes
fun getUserSwitcherActionIconResourceId(
@@ -50,6 +39,7 @@
isGuest: Boolean,
isAddSupervisedUser: Boolean,
isTablet: Boolean = false,
+ isManageUsers: Boolean,
): Int {
return if (isAddUser && isTablet) {
R.drawable.ic_account_circle_filled
@@ -59,6 +49,8 @@
R.drawable.ic_account_circle
} else if (isAddSupervisedUser) {
R.drawable.ic_add_supervised_user
+ } else if (isManageUsers) {
+ R.drawable.ic_manage_users
} else {
R.drawable.ic_avatar_user
}
@@ -85,6 +77,7 @@
isAddUser = record.isAddUser,
isAddSupervisedUser = record.isAddSupervisedUser,
isTablet = isTablet,
+ isManageUsers = record.isManageUsers,
)
)
}
@@ -114,8 +107,9 @@
isAddUser: Boolean,
isAddSupervisedUser: Boolean,
isTablet: Boolean = false,
+ isManageUsers: Boolean,
): Int {
- check(isGuest || isAddUser || isAddSupervisedUser)
+ check(isGuest || isAddUser || isAddSupervisedUser || isManageUsers)
return when {
isGuest && isGuestUserAutoCreated && isGuestUserResetting ->
@@ -125,6 +119,7 @@
isGuest -> com.android.internal.R.string.guest_name
isAddUser -> com.android.settingslib.R.string.user_add_user
isAddSupervisedUser -> R.string.add_user_supervised
+ isManageUsers -> R.string.manage_users
else -> error("This should never happen!")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
index 5b83df7..219dae2 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
@@ -19,7 +19,6 @@
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
-import com.android.systemui.R
import com.android.systemui.common.ui.drawable.CircularDrawable
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -30,6 +29,7 @@
import com.android.systemui.user.shared.model.UserActionModel
import com.android.systemui.user.shared.model.UserModel
import javax.inject.Inject
+import kotlin.math.ceil
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
@@ -52,8 +52,7 @@
userInteractor.users.map { models -> models.map { user -> toViewModel(user) } }
/** The maximum number of columns that the user selection grid should use. */
- val maximumUserColumns: Flow<Int> =
- users.map { LegacyUserUiHelper.getMaxUserSwitcherItemColumns(it.size) }
+ val maximumUserColumns: Flow<Int> = users.map { getMaxUserSwitcherItemColumns(it.size) }
private val _isMenuVisible = MutableStateFlow(false)
/**
@@ -118,6 +117,15 @@
_isMenuVisible.value = false
}
+ /** Returns the maximum number of columns for user items in the user switcher. */
+ private fun getMaxUserSwitcherItemColumns(userCount: Int): Int {
+ return if (userCount < 5) {
+ 4
+ } else {
+ ceil(userCount / 2.0).toInt()
+ }
+ }
+
private fun createFinishRequestedFlow(): Flow<Boolean> {
var mostRecentSelectedUserId: Int? = null
var mostRecentIsInteractive: Boolean? = null
@@ -171,27 +179,23 @@
return UserActionViewModel(
viewKey = model.ordinal.toLong(),
iconResourceId =
- if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
- R.drawable.ic_manage_users
- } else {
- LegacyUserUiHelper.getUserSwitcherActionIconResourceId(
- isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
- isAddUser = model == UserActionModel.ADD_USER,
- isGuest = model == UserActionModel.ENTER_GUEST_MODE,
- )
- },
+ LegacyUserUiHelper.getUserSwitcherActionIconResourceId(
+ isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
+ isAddUser = model == UserActionModel.ADD_USER,
+ isGuest = model == UserActionModel.ENTER_GUEST_MODE,
+ isManageUsers = model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+ isTablet = true,
+ ),
textResourceId =
- if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
- R.string.manage_users
- } else {
- LegacyUserUiHelper.getUserSwitcherActionTextResourceId(
- isGuest = model == UserActionModel.ENTER_GUEST_MODE,
- isGuestUserAutoCreated = guestUserInteractor.isGuestUserAutoCreated,
- isGuestUserResetting = guestUserInteractor.isGuestUserResetting,
- isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
- isAddUser = model == UserActionModel.ADD_USER,
- )
- },
+ LegacyUserUiHelper.getUserSwitcherActionTextResourceId(
+ isGuest = model == UserActionModel.ENTER_GUEST_MODE,
+ isGuestUserAutoCreated = guestUserInteractor.isGuestUserAutoCreated,
+ isGuestUserResetting = guestUserInteractor.isGuestUserResetting,
+ isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
+ isAddUser = model == UserActionModel.ADD_USER,
+ isManageUsers = model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+ isTablet = true,
+ ),
onClicked = {
userInteractor.executeAction(action = model)
// We don't finish because we want to show a dialog over the full-screen UI and
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index c6ebaa8..48e8239 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -221,15 +221,17 @@
public void onResourcesUpdate_callsThroughOnRotationChange() {
// Rotation is the same, shouldn't cause an update
mKeyguardSecurityContainerController.updateResources();
- verify(mView, never()).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
- mUserSwitcherController);
+ verify(mView, never()).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
+ eq(mUserSwitcherController),
+ any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
// Update rotation. Should trigger update
mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
mKeyguardSecurityContainerController.updateResources();
- verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
- mUserSwitcherController);
+ verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
+ eq(mUserSwitcherController),
+ any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
}
private void touchDown() {
@@ -263,8 +265,9 @@
.thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
- verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
- mUserSwitcherController);
+ verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
+ eq(mUserSwitcherController),
+ any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
}
@Test
@@ -275,8 +278,9 @@
.thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController);
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
- verify(mView).initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager,
- mUserSwitcherController);
+ verify(mView).initMode(eq(MODE_ONE_HANDED), eq(mGlobalSettings), eq(mFalsingManager),
+ eq(mUserSwitcherController),
+ any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
}
@Test
@@ -285,8 +289,26 @@
setupGetSecurityView();
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password);
- verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
- mUserSwitcherController);
+ verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
+ eq(mUserSwitcherController),
+ any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
+ }
+
+ @Test
+ public void addUserSwitcherCallback() {
+ ArgumentCaptor<KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback>
+ captor = ArgumentCaptor.forClass(
+ KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class);
+
+ setupGetSecurityView();
+
+ mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password);
+ verify(mView).initMode(anyInt(), any(GlobalSettings.class), any(FalsingManager.class),
+ any(UserSwitcherController.class),
+ captor.capture());
+ captor.getValue().showUnlockToContinueMessage();
+ verify(mKeyguardPasswordViewControllerMock).showMessage(
+ getContext().getString(R.string.keyguard_unlock_to_continue), null);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 52f8825..82d3ca7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -119,7 +119,7 @@
int systemBarInsetAmount = 0;
mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
- mUserSwitcherController);
+ mUserSwitcherController, () -> {});
Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
@@ -141,7 +141,7 @@
int systemBarInsetAmount = paddingBottom + 1;
mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
- mUserSwitcherController);
+ mUserSwitcherController, () -> {});
Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
@@ -158,9 +158,10 @@
@Test
public void testDefaultViewMode() {
mKeyguardSecurityContainer.initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager,
- mUserSwitcherController);
+ mUserSwitcherController, () -> {
+ });
mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
- mUserSwitcherController);
+ mUserSwitcherController, () -> {});
ConstraintSet.Constraint viewFlipperConstraint =
getViewConstraint(mSecurityViewFlipper.getId());
assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID);
@@ -377,7 +378,7 @@
private void setupUserSwitcher() {
when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_RIGHT);
mKeyguardSecurityContainer.initMode(KeyguardSecurityContainer.MODE_USER_SWITCHER,
- mGlobalSettings, mFalsingManager, mUserSwitcherController);
+ mGlobalSettings, mFalsingManager, mUserSwitcherController, () -> {});
}
private ArrayList<UserRecord> buildUserRecords(int count) {
@@ -387,7 +388,8 @@
0 /* flags */);
users.add(new UserRecord(info, null, false /* isGuest */, false /* isCurrent */,
false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */,
- false /* isAddSupervisedUser */, null /* enforcedAdmin */));
+ false /* isAddSupervisedUser */, null /* enforcedAdmin */,
+ false /* isManageUsers */));
}
return users;
}
@@ -395,7 +397,7 @@
private void setupForUpdateKeyguardPosition(boolean oneHandedMode) {
int mode = oneHandedMode ? MODE_ONE_HANDED : MODE_DEFAULT;
mKeyguardSecurityContainer.initMode(mode, mGlobalSettings, mFalsingManager,
- mUserSwitcherController);
+ mUserSwitcherController, () -> {});
}
/** Get the ConstraintLayout constraint of the view. */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index d52612b..f2ae7a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -35,6 +35,8 @@
import android.view.WindowManager
import android.widget.ScrollView
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.R
@@ -143,6 +145,35 @@
}
@Test
+ fun testDismissesOnFocusLoss_hidesKeyboardWhenVisible() {
+ val container = initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
+ waitForIdleSync()
+
+ val requestID = authContainer?.requestId ?: 0L
+
+ // Simulate keyboard was shown on the credential view
+ val windowInsetsController = container.windowInsetsController
+ spyOn(windowInsetsController)
+ spyOn(container.rootWindowInsets)
+ doReturn(true).`when`(container.rootWindowInsets).isVisible(WindowInsets.Type.ime())
+
+ container.onWindowFocusChanged(false)
+ waitForIdleSync()
+
+ // Expect hiding IME request will be invoked when dismissing the view
+ verify(windowInsetsController)?.hide(WindowInsets.Type.ime())
+
+ verify(callback).onDismissed(
+ eq(AuthDialogCallback.DISMISSED_USER_CANCELED),
+ eq<ByteArray?>(null), /* credentialAttestation */
+ eq(requestID)
+ )
+ assertThat(container.parent).isNull()
+ }
+
+ @Test
fun testActionAuthenticated_sendsDismissedAuthenticated() {
val container = initializeFingerprintContainer()
container.mBiometricCallback.onAction(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorParameterizedTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index b6d7559..b4d5464 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -12,20 +12,20 @@
* 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.usecase
+package com.android.systemui.keyguard.domain.interactor
import android.content.Intent
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
@@ -195,6 +195,7 @@
@Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
+ @Mock private lateinit var expandable: Expandable
private lateinit var underTest: KeyguardQuickAffordanceInteractor
@@ -208,6 +209,7 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ whenever(expandable.activityLaunchController()).thenReturn(animationController)
homeControls = object : FakeKeyguardQuickAffordanceConfig() {}
underTest =
@@ -259,7 +261,7 @@
underTest.onQuickAffordanceClicked(
configKey = homeControls::class,
- animationController = animationController,
+ expandable = expandable,
)
if (startActivity) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
similarity index 95%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 1dd919a..65fd6e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -12,9 +12,10 @@
* 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.usecase
+package com.android.systemui.keyguard.domain.interactor
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
@@ -22,13 +23,12 @@
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordancePosition
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -103,6 +103,7 @@
homeControls.setState(
KeyguardQuickAffordanceConfig.State.Visible(
icon = ICON,
+ toggle = KeyguardQuickAffordanceToggleState.On,
)
)
@@ -123,6 +124,7 @@
assertThat(visibleModel.icon).isEqualTo(ICON)
assertThat(visibleModel.icon.contentDescription)
.isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
+ assertThat(visibleModel.toggle).isEqualTo(KeyguardQuickAffordanceToggleState.On)
job.cancel()
}
@@ -152,6 +154,7 @@
assertThat(visibleModel.icon).isEqualTo(ICON)
assertThat(visibleModel.icon.contentDescription)
.isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
+ assertThat(visibleModel.toggle).isEqualTo(KeyguardQuickAffordanceToggleState.NotSupported)
job.cancel()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
index 6ea1daa..e99c139 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt
@@ -17,7 +17,7 @@
package com.android.systemui.keyguard.domain.quickaffordance
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -40,7 +40,7 @@
override val state: Flow<KeyguardQuickAffordanceConfig.State> = _state
override fun onQuickAffordanceClicked(
- animationController: ActivityLaunchAnimator.Controller?,
+ expandable: Expandable?,
): OnClickedResult {
return onClickedResult
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index dede4ec..a809f05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -20,7 +20,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig.OnClickedResult
@@ -44,7 +44,7 @@
class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
@Mock private lateinit var component: ControlsComponent
- @Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
+ @Mock private lateinit var expandable: Expandable
private lateinit var underTest: HomeControlsKeyguardQuickAffordanceConfig
@@ -103,7 +103,7 @@
fun `onQuickAffordanceClicked - canShowWhileLockedSetting is true`() = runBlockingTest {
whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true))
- val onClickedResult = underTest.onQuickAffordanceClicked(animationController)
+ val onClickedResult = underTest.onQuickAffordanceClicked(expandable)
assertThat(onClickedResult).isInstanceOf(OnClickedResult.StartActivity::class.java)
assertThat((onClickedResult as OnClickedResult.StartActivity).canShowWhileLocked).isTrue()
@@ -113,7 +113,7 @@
fun `onQuickAffordanceClicked - canShowWhileLockedSetting is false`() = runBlockingTest {
whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
- val onClickedResult = underTest.onQuickAffordanceClicked(animationController)
+ val onClickedResult = underTest.onQuickAffordanceClicked(expandable)
assertThat(onClickedResult).isInstanceOf(OnClickedResult.StartActivity::class.java)
assertThat((onClickedResult as OnClickedResult.StartActivity).canShowWhileLocked).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
index 0a4478f..98dc4c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
@@ -24,11 +24,13 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.wallet.controller.QuickAccessWalletController
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
@@ -40,7 +42,6 @@
import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
@@ -135,8 +136,11 @@
@Test
fun onQuickAffordanceClicked() {
val animationController: ActivityLaunchAnimator.Controller = mock()
+ val expandable: Expandable = mock {
+ whenever(this.activityLaunchController()).thenReturn(animationController)
+ }
- assertThat(underTest.onQuickAffordanceClicked(animationController))
+ assertThat(underTest.onQuickAffordanceClicked(expandable))
.isEqualTo(KeyguardQuickAffordanceConfig.OnClickedResult.Handled)
verify(walletController)
.startQuickAccessUiIntent(
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 96544e7..d674c89 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
@@ -20,7 +20,7 @@
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.doze.util.BurnInHelperWrapper
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -31,6 +31,7 @@
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordanceToggleState
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -59,7 +60,7 @@
@RunWith(JUnit4::class)
class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
- @Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
+ @Mock private lateinit var expandable: Expandable
@Mock private lateinit var burnInHelperWrapper: BurnInHelperWrapper
@Mock private lateinit var lockPatternUtils: LockPatternUtils
@Mock private lateinit var keyguardStateController: KeyguardStateController
@@ -130,6 +131,7 @@
TestConfig(
isVisible = true,
isClickable = true,
+ isActivated = true,
icon = mock(),
canShowWhileLocked = false,
intent = Intent("action"),
@@ -505,6 +507,12 @@
}
KeyguardQuickAffordanceConfig.State.Visible(
icon = testConfig.icon ?: error("Icon is unexpectedly null!"),
+ toggle =
+ when (testConfig.isActivated) {
+ true -> KeyguardQuickAffordanceToggleState.On
+ false -> KeyguardQuickAffordanceToggleState.Off
+ null -> KeyguardQuickAffordanceToggleState.NotSupported
+ }
)
} else {
KeyguardQuickAffordanceConfig.State.Hidden
@@ -521,12 +529,13 @@
checkNotNull(viewModel)
assertThat(viewModel.isVisible).isEqualTo(testConfig.isVisible)
assertThat(viewModel.isClickable).isEqualTo(testConfig.isClickable)
+ assertThat(viewModel.isActivated).isEqualTo(testConfig.isActivated)
if (testConfig.isVisible) {
assertThat(viewModel.icon).isEqualTo(testConfig.icon)
viewModel.onClicked.invoke(
KeyguardQuickAffordanceViewModel.OnClickedParameters(
configKey = configKey,
- animationController = animationController,
+ expandable = expandable,
)
)
if (testConfig.intent != null) {
@@ -542,6 +551,7 @@
private data class TestConfig(
val isVisible: Boolean,
val isClickable: Boolean = false,
+ val isActivated: Boolean = false,
val icon: Icon? = null,
val canShowWhileLocked: Boolean = false,
val intent: Intent? = null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 0e9d279..6adce7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -80,6 +80,7 @@
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.DeadZone;
@@ -197,6 +198,8 @@
@Mock
private UserContextProvider mUserContextProvider;
@Mock
+ private WakefulnessLifecycle mWakefulnessLifecycle;
+ @Mock
private Resources mResources;
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
private DeviceConfigProxyFake mDeviceConfigProxyFake = new DeviceConfigProxyFake();
@@ -474,7 +477,8 @@
mNavigationBarTransitions,
mEdgeBackGestureHandler,
Optional.of(mock(BackAnimation.class)),
- mUserContextProvider));
+ mUserContextProvider,
+ mWakefulnessLifecycle));
}
private void processAllMessages() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 4e9b232..c377c37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -46,6 +46,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.power.PowerUI.WarningsUI;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -84,6 +85,7 @@
private PowerUI mPowerUI;
@Mock private EnhancedEstimates mEnhancedEstimates;
@Mock private PowerManager mPowerManager;
+ @Mock private WakefulnessLifecycle mWakefulnessLifecycle;
@Mock private IThermalService mThermalServiceMock;
private IThermalEventListener mUsbThermalEventListener;
private IThermalEventListener mSkinThermalEventListener;
@@ -680,7 +682,7 @@
private void createPowerUi() {
mPowerUI = new PowerUI(
mContext, mBroadcastDispatcher, mCommandQueue, mCentralSurfacesOptionalLazy,
- mMockWarnings, mEnhancedEstimates, mPowerManager);
+ mMockWarnings, mEnhancedEstimates, mWakefulnessLifecycle, mPowerManager);
mPowerUI.mThermalService = mThermalServiceMock;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
index 2a4996f..760bb9b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
@@ -192,16 +192,6 @@
// UserManager change.
assertThat(iconTint()).isNull()
- // Trigger a user info change: there should now be a tint.
- userInfoController.updateInfo { userAccount = "doe" }
- assertThat(iconTint())
- .isEqualTo(
- Utils.getColorAttrDefaultColor(
- context,
- android.R.attr.colorForeground,
- )
- )
-
// Make sure we don't tint the icon if it is a user image (and not the default image), even
// in guest mode.
userInfoController.updateInfo { this.picture = mock<UserIconDrawable>() }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
new file mode 100644
index 0000000..c6ce51a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DraggableConstraintLayoutTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.screenshot;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.MotionEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class DraggableConstraintLayoutTest extends SysuiTestCase {
+
+ @Mock
+ DraggableConstraintLayout.SwipeDismissCallbacks mCallbacks;
+
+ private DraggableConstraintLayout mDraggableConstraintLayout;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mDraggableConstraintLayout = new DraggableConstraintLayout(mContext, null, 0);
+ }
+
+ @Test
+ public void test_dismissDoesNotCallSwipeInitiated() {
+ mDraggableConstraintLayout.setCallbacks(mCallbacks);
+
+ mDraggableConstraintLayout.dismiss();
+
+ verify(mCallbacks, never()).onSwipeDismissInitiated(any());
+ }
+
+ @Test
+ public void test_onTouchCallsOnInteraction() {
+ mDraggableConstraintLayout.setCallbacks(mCallbacks);
+
+ mDraggableConstraintLayout.onInterceptTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));
+
+ verify(mCallbacks).onInteraction();
+ }
+
+ @Test
+ public void test_callbacksNotSet() {
+ // just test that it doesn't throw an NPE
+ mDraggableConstraintLayout.onInterceptTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0));
+ mDraggableConstraintLayout.onInterceptHoverEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0));
+ mDraggableConstraintLayout.dismiss();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
index 3f641df..ca65987 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
@@ -91,6 +91,8 @@
verifyNoMoreInteractions(mLogger);
clearInvocations(mLogger);
+ when(mBindStage.tryGetStageParams(eq(mEntry))).thenReturn(new RowContentBindParams());
+
mViewBinder.unbindHeadsUpView(mEntry);
verify(mLogger).entryContentViewMarkedFreeable(eq(mEntry));
verifyNoMoreInteractions(mLogger);
@@ -139,6 +141,8 @@
verifyNoMoreInteractions(mLogger);
clearInvocations(mLogger);
+ when(mBindStage.tryGetStageParams(eq(mEntry))).thenReturn(new RowContentBindParams());
+
mViewBinder.unbindHeadsUpView(mEntry);
verify(mLogger).currentOngoingBindingAborted(eq(mEntry));
verify(mLogger).entryContentViewMarkedFreeable(eq(mEntry));
@@ -150,4 +154,30 @@
verifyNoMoreInteractions(mLogger);
clearInvocations(mLogger);
}
+
+ @Test
+ public void testLoggingForLateUnbindFlow() {
+ AtomicReference<NotifBindPipeline.BindCallback> callback = new AtomicReference<>();
+ when(mBindStage.requestRebind(any(), any())).then(i -> {
+ callback.set(i.getArgument(1));
+ return new CancellationSignal();
+ });
+
+ mViewBinder.bindHeadsUpView(mEntry, null);
+ verify(mLogger).startBindingHun(eq(mEntry));
+ verifyNoMoreInteractions(mLogger);
+ clearInvocations(mLogger);
+
+ callback.get().onBindFinished(mEntry);
+ verify(mLogger).entryBoundSuccessfully(eq(mEntry));
+ verifyNoMoreInteractions(mLogger);
+ clearInvocations(mLogger);
+
+ when(mBindStage.tryGetStageParams(eq(mEntry))).thenReturn(null);
+
+ mViewBinder.unbindHeadsUpView(mEntry);
+ verify(mLogger).entryBindStageParamsNullOnUnbind(eq(mEntry));
+ verifyNoMoreInteractions(mLogger);
+ clearInvocations(mLogger);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
index ad3bd71..7c99568 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
@@ -21,6 +21,10 @@
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNotSame;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -31,6 +35,7 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.Log;
import androidx.test.filters.SmallTest;
@@ -100,6 +105,67 @@
verify(mBinder).unbindContent(eq(mEntry), any(), eq(flags));
}
+ class CountingWtfHandler implements Log.TerribleFailureHandler {
+ private Log.TerribleFailureHandler mOldHandler = null;
+ private int mWtfCount = 0;
+
+ public void register() {
+ mOldHandler = Log.setWtfHandler(this);
+ }
+
+ public void unregister() {
+ Log.setWtfHandler(mOldHandler);
+ mOldHandler = null;
+ }
+
+ @Override
+ public void onTerribleFailure(String tag, Log.TerribleFailure what, boolean system) {
+ mWtfCount++;
+ }
+
+ public int getWtfCount() {
+ return mWtfCount;
+ }
+ }
+
+ @Test
+ public void testGetStageParamsAfterCleanUp() {
+ // GIVEN an entry whose params have already been deleted.
+ RowContentBindParams originalParams = mRowContentBindStage.getStageParams(mEntry);
+ mRowContentBindStage.deleteStageParams(mEntry);
+
+ // WHEN a caller calls getStageParams.
+ CountingWtfHandler countingWtfHandler = new CountingWtfHandler();
+ countingWtfHandler.register();
+
+ RowContentBindParams blankParams = mRowContentBindStage.getStageParams(mEntry);
+
+ countingWtfHandler.unregister();
+
+ // THEN getStageParams logs a WTF and returns blank params created to avoid a crash.
+ assertEquals(1, countingWtfHandler.getWtfCount());
+ assertNotNull(blankParams);
+ assertNotSame(originalParams, blankParams);
+ }
+
+ @Test
+ public void testTryGetStageParamsAfterCleanUp() {
+ // GIVEN an entry whose params have already been deleted.
+ mRowContentBindStage.deleteStageParams(mEntry);
+
+ // WHEN a caller calls getStageParams.
+ CountingWtfHandler countingWtfHandler = new CountingWtfHandler();
+ countingWtfHandler.register();
+
+ RowContentBindParams nullParams = mRowContentBindStage.tryGetStageParams(mEntry);
+
+ countingWtfHandler.unregister();
+
+ // THEN getStageParams does NOT log a WTF and returns null to indicate missing params.
+ assertEquals(0, countingWtfHandler.getWtfCount());
+ assertNull(nullParams);
+ }
+
@Test
public void testRebindAllContentViews() {
// GIVEN a view with content bound.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt
index 76ecc1c..169f4fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt
@@ -57,14 +57,18 @@
import com.android.systemui.shade.NotificationShadeWindowView
import com.android.systemui.telephony.TelephonyListenerManager
import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.legacyhelper.data.LegacyUserDataHelper
+import com.android.systemui.user.shared.model.UserActionModel
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.kotlinArgumentCaptor
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
@@ -123,7 +127,7 @@
private val ownerId = UserHandle.USER_SYSTEM
private val ownerInfo = UserInfo(ownerId, "Owner", null,
UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL or UserInfo.FLAG_INITIALIZED or
- UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM,
+ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM or UserInfo.FLAG_ADMIN,
UserManager.USER_TYPE_FULL_SYSTEM)
private val guestId = 1234
private val guestInfo = UserInfo(guestId, "Guest", null,
@@ -597,6 +601,76 @@
}
@Test
+ fun testCanManageUser_userSwitcherEnabled_addUserWhenLocked() {
+ `when`(
+ globalSettings.getIntForUser(
+ eq(Settings.Global.USER_SWITCHER_ENABLED),
+ anyInt(),
+ eq(UserHandle.USER_SYSTEM)
+ )
+ ).thenReturn(1)
+
+ `when`(
+ globalSettings.getIntForUser(
+ eq(Settings.Global.ADD_USERS_WHEN_LOCKED),
+ anyInt(),
+ eq(UserHandle.USER_SYSTEM)
+ )
+ ).thenReturn(1)
+ setupController()
+ assertTrue(userSwitcherController.canManageUsers())
+ }
+
+ @Test
+ fun testCanManageUser_userSwitcherDisabled_addUserWhenLocked() {
+ `when`(
+ globalSettings.getIntForUser(
+ eq(Settings.Global.USER_SWITCHER_ENABLED),
+ anyInt(),
+ eq(UserHandle.USER_SYSTEM)
+ )
+ ).thenReturn(0)
+
+ `when`(
+ globalSettings.getIntForUser(
+ eq(Settings.Global.ADD_USERS_WHEN_LOCKED),
+ anyInt(),
+ eq(UserHandle.USER_SYSTEM)
+ )
+ ).thenReturn(1)
+ setupController()
+ assertFalse(userSwitcherController.canManageUsers())
+ }
+
+ @Test
+ fun testCanManageUser_userSwitcherEnabled_isAdmin() {
+ `when`(
+ globalSettings.getIntForUser(
+ eq(Settings.Global.USER_SWITCHER_ENABLED),
+ anyInt(),
+ eq(UserHandle.USER_SYSTEM)
+ )
+ ).thenReturn(1)
+
+ setupController()
+ assertTrue(userSwitcherController.canManageUsers())
+ }
+
+ @Test
+ fun testCanManageUser_userSwitcherDisabled_isAdmin() {
+ `when`(
+ globalSettings.getIntForUser(
+ eq(Settings.Global.USER_SWITCHER_ENABLED),
+ anyInt(),
+ eq(UserHandle.USER_SYSTEM)
+ )
+ ).thenReturn(0)
+
+ setupController()
+ assertFalse(userSwitcherController.canManageUsers())
+ }
+
+ @Test
fun addUserSwitchCallback() {
val broadcastReceiverCaptor = argumentCaptor<BroadcastReceiver>()
verify(broadcastDispatcher).registerReceiver(
@@ -632,4 +706,22 @@
bgExecutor.runAllReady()
verify(userManager).createGuest(context)
}
+
+ @Test
+ fun onUserItemClicked_manageUsers() {
+ val manageUserRecord = LegacyUserDataHelper.createRecord(
+ mContext,
+ ownerId,
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+ isRestricted = false,
+ isSwitchToEnabled = true
+ )
+
+ userSwitcherController.onUserListItemClicked(manageUserRecord, null)
+ val intentCaptor = kotlinArgumentCaptor<Intent>()
+ verify(activityStarter).startActivity(intentCaptor.capture(),
+ eq(true)
+ )
+ Truth.assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
deleted file mode 100644
index 3968bb7..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
+++ /dev/null
@@ -1,152 +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.user
-
-import android.app.Application
-import android.os.UserManager
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper.RunWithLooper
-import android.view.LayoutInflater
-import android.view.View
-import android.view.Window
-import android.window.OnBackInvokedCallback
-import android.window.OnBackInvokedDispatcher
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.policy.UserSwitcherController
-import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.time.FakeSystemClock
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.Mockito.any
-import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.doNothing
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import java.util.concurrent.Executor
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@RunWithLooper(setAsMainLooper = true)
-class UserSwitcherActivityTest : SysuiTestCase() {
- @Mock
- private lateinit var activity: UserSwitcherActivity
- @Mock
- private lateinit var userSwitcherController: UserSwitcherController
- @Mock
- private lateinit var broadcastDispatcher: BroadcastDispatcher
- @Mock
- private lateinit var layoutInflater: LayoutInflater
- @Mock
- private lateinit var falsingCollector: FalsingCollector
- @Mock
- private lateinit var falsingManager: FalsingManager
- @Mock
- private lateinit var userManager: UserManager
- @Mock
- private lateinit var userTracker: UserTracker
- @Mock
- private lateinit var flags: FeatureFlags
- @Mock
- private lateinit var viewModelFactoryLazy: dagger.Lazy<UserSwitcherViewModel.Factory>
- @Mock
- private lateinit var onBackDispatcher: OnBackInvokedDispatcher
- @Mock
- private lateinit var decorView: View
- @Mock
- private lateinit var window: Window
- @Mock
- private lateinit var userSwitcherRootView: UserSwitcherRootView
- @Captor
- private lateinit var onBackInvokedCallback: ArgumentCaptor<OnBackInvokedCallback>
- var isFinished = false
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- activity = spy(object : UserSwitcherActivity(
- userSwitcherController,
- broadcastDispatcher,
- falsingCollector,
- falsingManager,
- userManager,
- userTracker,
- flags,
- viewModelFactoryLazy,
- ) {
- override fun getOnBackInvokedDispatcher() = onBackDispatcher
- override fun getMainExecutor(): Executor = FakeExecutor(FakeSystemClock())
- override fun finish() {
- isFinished = true
- }
- })
- `when`(activity.window).thenReturn(window)
- `when`(window.decorView).thenReturn(decorView)
- `when`(activity.findViewById<UserSwitcherRootView>(R.id.user_switcher_root))
- .thenReturn(userSwitcherRootView)
- `when`(activity.findViewById<View>(R.id.cancel)).thenReturn(mock(View::class.java))
- `when`(activity.findViewById<View>(R.id.add)).thenReturn(mock(View::class.java))
- `when`(activity.application).thenReturn(mock(Application::class.java))
- doNothing().`when`(activity).setContentView(anyInt())
- }
-
- @Test
- fun testMaxColumns() {
- assertThat(activity.getMaxColumns(3)).isEqualTo(4)
- assertThat(activity.getMaxColumns(4)).isEqualTo(4)
- assertThat(activity.getMaxColumns(5)).isEqualTo(3)
- assertThat(activity.getMaxColumns(6)).isEqualTo(3)
- assertThat(activity.getMaxColumns(7)).isEqualTo(4)
- assertThat(activity.getMaxColumns(9)).isEqualTo(5)
- }
-
- @Test
- fun onCreate_callbackRegistration() {
- activity.createActivity()
- verify(onBackDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any())
-
- activity.destroyActivity()
- verify(onBackDispatcher).unregisterOnBackInvokedCallback(any())
- }
-
- @Test
- fun onBackInvokedCallback_finishesActivity() {
- activity.createActivity()
- verify(onBackDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), onBackInvokedCallback.capture())
-
- onBackInvokedCallback.value.onBackInvoked()
- assertThat(isFinished).isTrue()
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt
index 37c378c..1540f85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt
@@ -202,6 +202,7 @@
fun `actions - device unlocked`() =
runBlocking(IMMEDIATE) {
val userInfos = createUserInfos(count = 2, includeGuest = false)
+
userRepository.setUserInfos(userInfos)
userRepository.setSelectedUserInfo(userInfos[0])
userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
@@ -215,6 +216,7 @@
UserActionModel.ENTER_GUEST_MODE,
UserActionModel.ADD_USER,
UserActionModel.ADD_SUPERVISED_USER,
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
)
)
@@ -276,6 +278,7 @@
UserActionModel.ENTER_GUEST_MODE,
UserActionModel.ADD_USER,
UserActionModel.ADD_SUPERVISED_USER,
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
)
)
@@ -283,7 +286,7 @@
}
@Test
- fun `actions - device locked - only guest action is shown`() =
+ fun `actions - device locked - only guest action and manage user is shown`() =
runBlocking(IMMEDIATE) {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -293,7 +296,13 @@
var value: List<UserActionModel>? = null
val job = underTest.actions.onEach { value = it }.launchIn(this)
- assertThat(value).isEqualTo(listOf(UserActionModel.ENTER_GUEST_MODE))
+ assertThat(value)
+ .isEqualTo(
+ listOf(
+ UserActionModel.ENTER_GUEST_MODE,
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT
+ )
+ )
job.cancel()
}
@@ -330,7 +339,7 @@
underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER)
val intentCaptor = kotlinArgumentCaptor<Intent>()
- verify(activityStarter).startActivity(intentCaptor.capture(), eq(false))
+ verify(activityStarter).startActivity(intentCaptor.capture(), eq(true))
assertThat(intentCaptor.value.action)
.isEqualTo(UserManager.ACTION_CREATE_SUPERVISED_USER)
assertThat(intentCaptor.value.`package`).isEqualTo(SUPERVISED_USER_CREATION_APP_PACKAGE)
@@ -342,7 +351,7 @@
underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
val intentCaptor = kotlinArgumentCaptor<Intent>()
- verify(activityStarter).startActivity(intentCaptor.capture(), eq(false))
+ verify(activityStarter).startActivity(intentCaptor.capture(), eq(true))
assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS)
}
@@ -561,6 +570,7 @@
UserActionModel.ENTER_GUEST_MODE,
UserActionModel.ADD_USER,
UserActionModel.ADD_SUPERVISED_USER,
+ UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
),
)
}
@@ -705,7 +715,7 @@
name,
/* iconPath= */ "",
/* flags= */ if (isPrimary) {
- UserInfo.FLAG_PRIMARY
+ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN
} else {
0
},
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index aec5f5e..4cf63b3 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -3732,21 +3732,34 @@
Slog.w(TAG, "agentDisconnected: the backup agent for " + packageName
+ " died: cancel current operations");
- // handleCancel() causes the PerformFullTransportBackupTask to go on to
- // tearDownAgentAndKill: that will unbindBackupAgent in the Activity Manager, so
- // that the package being backed up doesn't get stuck in restricted mode until the
- // backup time-out elapses.
- for (int token : mOperationStorage.operationTokensForPackage(packageName)) {
- if (MORE_DEBUG) {
- Slog.d(TAG, "agentDisconnected: will handleCancel(all) for token:"
- + Integer.toHexString(token));
+ // Offload operation cancellation off the main thread as the cancellation callbacks
+ // might call out to BackupTransport. Other operations started on the same package
+ // before the cancellation callback has executed will also be cancelled by the callback.
+ Runnable cancellationRunnable = () -> {
+ // handleCancel() causes the PerformFullTransportBackupTask to go on to
+ // tearDownAgentAndKill: that will unbindBackupAgent in the Activity Manager, so
+ // that the package being backed up doesn't get stuck in restricted mode until the
+ // backup time-out elapses.
+ for (int token : mOperationStorage.operationTokensForPackage(packageName)) {
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "agentDisconnected: will handleCancel(all) for token:"
+ + Integer.toHexString(token));
+ }
+ handleCancel(token, true /* cancelAll */);
}
- handleCancel(token, true /* cancelAll */);
- }
+ };
+ getThreadForAsyncOperation(/* operationName */ "agent-disconnected",
+ cancellationRunnable).start();
+
mAgentConnectLock.notifyAll();
}
}
+ @VisibleForTesting
+ Thread getThreadForAsyncOperation(String operationName, Runnable operation) {
+ return new Thread(operation, operationName);
+ }
+
/**
* An application being installed will need a restore pass, then the {@link PackageManager} will
* need to be told when the restore is finished.
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index fb8c5b1..41b62e6 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -363,7 +363,9 @@
@Override
public void handleMessage(@NonNull Message msg) {
final int associationId = msg.what;
- onDeviceGone(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+ if (mSimulated.contains(associationId)) {
+ onDeviceGone(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+ }
}
}
}
diff --git a/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
similarity index 99%
rename from core/java/com/android/server/SystemConfig.java
rename to services/core/java/com/android/server/SystemConfig.java
index 2c9ef4f..b7f8d38 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -72,6 +72,8 @@
* Loads global system configuration info.
* Note: Initializing this class hits the disk and is slow. This class should generally only be
* accessed by the system_server process.
+ *
+ * @hide
*/
public class SystemConfig {
static final String TAG = "SystemConfig";
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 593e21a5..1a4da7d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3937,7 +3937,8 @@
// Clear its scheduled jobs
JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
// Clearing data is a user-initiated action.
- js.cancelJobsForUid(appInfo.uid, JobParameters.STOP_REASON_USER,
+ js.cancelJobsForUid(appInfo.uid, /* includeProxiedJobs */ true,
+ JobParameters.STOP_REASON_USER,
JobParameters.INTERNAL_STOP_REASON_DATA_CLEARED, "clear data");
// Clear its pending alarms
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 23c020e..3c1bf0b 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -1138,10 +1138,7 @@
mHandler.removeCallbacksAndMessages(null);
// Release any outstanding wakelocks we're still holding because of pending messages.
- mWakelockController.releaseUnfinishedBusinessSuspendBlocker();
- mWakelockController.releaseStateChangedSuspendBlocker();
- mWakelockController.releaseProxPositiveSuspendBlocker();
- mWakelockController.releaseProxNegativeSuspendBlocker();
+ mWakelockController.releaseAll();
final float brightness = mPowerState != null
? mPowerState.getScreenBrightness()
@@ -1729,7 +1726,7 @@
// Grab a wake lock if we have unfinished business.
if (!finished) {
- mWakelockController.acquireUnfinishedBusinessSuspendBlocker();
+ mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
}
// Notify the power manager when ready.
@@ -1749,7 +1746,7 @@
// Release the wake lock when we have no unfinished business.
if (finished) {
- mWakelockController.releaseUnfinishedBusinessSuspendBlocker();
+ mWakelockController.releaseWakelock(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
}
// Record if dozing for future comparison.
@@ -2248,7 +2245,8 @@
mSensorManager.unregisterListener(mProximitySensorListener);
// release wake lock(must be last)
boolean proxDebounceSuspendBlockerReleased =
- mWakelockController.releaseProxDebounceSuspendBlocker();
+ mWakelockController.releaseWakelock(
+ WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
if (proxDebounceSuspendBlockerReleased) {
mPendingProximityDebounceTime = -1;
}
@@ -2272,11 +2270,13 @@
if (positive) {
mPendingProximity = PROXIMITY_POSITIVE;
mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
- mWakelockController.acquireProxDebounceSuspendBlocker(); // acquire wake lock
+ mWakelockController.acquireWakelock(
+ WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); // acquire wake lock
} else {
mPendingProximity = PROXIMITY_NEGATIVE;
mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
- mWakelockController.acquireProxDebounceSuspendBlocker(); // acquire wake lock
+ mWakelockController.acquireWakelock(
+ WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); // acquire wake lock
}
// Debounce the new sensor reading.
@@ -2300,7 +2300,8 @@
updatePowerState();
// (must be last)
boolean proxDebounceSuspendBlockerReleased =
- mWakelockController.releaseProxDebounceSuspendBlocker();
+ mWakelockController.releaseWakelock(
+ WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
if (proxDebounceSuspendBlockerReleased) {
mPendingProximityDebounceTime = -1;
}
@@ -2315,7 +2316,8 @@
}
private void sendOnStateChangedWithWakelock() {
- boolean wakeLockAcquired = mWakelockController.acquireStateChangedSuspendBlocker();
+ boolean wakeLockAcquired = mWakelockController.acquireWakelock(
+ WakelockController.WAKE_LOCK_STATE_CHANGED);
if (wakeLockAcquired) {
mHandler.post(mWakelockController.getOnStateChangedRunnable());
}
@@ -2479,13 +2481,13 @@
}
private void sendOnProximityPositiveWithWakelock() {
- mWakelockController.acquireProxPositiveSuspendBlocker();
+ mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_PROXIMITY_POSITIVE);
mHandler.post(mWakelockController.getOnProximityPositiveRunnable());
}
private void sendOnProximityNegativeWithWakelock() {
- mWakelockController.acquireProxNegativeSuspendBlocker();
+ mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_PROXIMITY_NEGATIVE);
mHandler.post(mWakelockController.getOnProximityNegativeRunnable());
}
diff --git a/services/core/java/com/android/server/display/WakelockController.java b/services/core/java/com/android/server/display/WakelockController.java
index cbf559f..6511f4f 100644
--- a/services/core/java/com/android/server/display/WakelockController.java
+++ b/services/core/java/com/android/server/display/WakelockController.java
@@ -16,12 +16,15 @@
package com.android.server.display;
+import android.annotation.IntDef;
import android.hardware.display.DisplayManagerInternal;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* A utility class to acquire/release suspend blockers and manage appropriate states around it.
@@ -29,8 +32,26 @@
* display states as needed.
*/
public final class WakelockController {
+ public static final int WAKE_LOCK_PROXIMITY_POSITIVE = 1;
+ public static final int WAKE_LOCK_PROXIMITY_NEGATIVE = 2;
+ public static final int WAKE_LOCK_PROXIMITY_DEBOUNCE = 3;
+ public static final int WAKE_LOCK_STATE_CHANGED = 4;
+ public static final int WAKE_LOCK_UNFINISHED_BUSINESS = 5;
+
+ private static final int WAKE_LOCK_MAX = WAKE_LOCK_UNFINISHED_BUSINESS;
private static final boolean DEBUG = false;
+ @IntDef(flag = true, prefix = "WAKE_LOCK_", value = {
+ WAKE_LOCK_PROXIMITY_POSITIVE,
+ WAKE_LOCK_PROXIMITY_NEGATIVE,
+ WAKE_LOCK_PROXIMITY_DEBOUNCE,
+ WAKE_LOCK_STATE_CHANGED,
+ WAKE_LOCK_UNFINISHED_BUSINESS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WAKE_LOCK_TYPE {
+ }
+
// Asynchronous callbacks into the power manager service.
// Only invoked from the handler thread while no locks are held.
private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks;
@@ -58,17 +79,17 @@
// (i.e. DisplayPowerController2).
private boolean mOnStateChangedPending;
- // Count of positive proximity messages currently held. Used to keep track of how many
- // suspend blocker acquisitions are pending when shutting down the DisplayPowerController2.
- // Should only be accessed on the Handler thread of the class managing the Display states
- // (i.e. DisplayPowerController2).
- private int mOnProximityPositiveMessages;
+ // When true, it implies that a positive proximity wakelock is currently held. Used to keep
+ // track if suspend blocker acquisitions is pending when shutting down the
+ // DisplayPowerController2. Should only be accessed on the Handler thread of the class
+ // managing the Display states (i.e. DisplayPowerController2).
+ private boolean mIsProximityPositiveAcquired;
- // Count of negative proximity messages currently held. Used to keep track of how many
- // suspend blocker acquisitions are pending when shutting down the DisplayPowerController2.
- // Should only be accessed on the Handler thread of the class managing the Display states
- // (i.e. DisplayPowerController2).
- private int mOnProximityNegativeMessages;
+ // When true, it implies that a negative proximity wakelock is currently held. Used to keep
+ // track if suspend blocker acquisitions is pending when shutting down the
+ // DisplayPowerController2. Should only be accessed on the Handler thread of the class
+ // managing the Display states (i.e. DisplayPowerController2).
+ private boolean mIsProximityNegativeAcquired;
/**
* The constructor of WakelockController. Manages the initialization of all the local entities
@@ -87,9 +108,86 @@
}
/**
+ * A utility to acquire a wakelock
+ *
+ * @param wakelock The type of Wakelock to be acquired
+ * @return True of the wakelock is successfully acquired. False if it is already acquired
+ */
+ public boolean acquireWakelock(@WAKE_LOCK_TYPE int wakelock) {
+ return acquireWakelockInternal(wakelock);
+ }
+
+ /**
+ * A utility to release a wakelock
+ *
+ * @param wakelock The type of Wakelock to be released
+ * @return True of an acquired wakelock is successfully released. False if it is already
+ * acquired
+ */
+ public boolean releaseWakelock(@WAKE_LOCK_TYPE int wakelock) {
+ return releaseWakelockInternal(wakelock);
+ }
+
+ /**
+ * A utility to release all the wakelock acquired by the system
+ */
+ public void releaseAll() {
+ for (int i = WAKE_LOCK_PROXIMITY_POSITIVE; i < WAKE_LOCK_MAX; i++) {
+ releaseWakelockInternal(i);
+ }
+ }
+
+ private boolean acquireWakelockInternal(@WAKE_LOCK_TYPE int wakelock) {
+ switch (wakelock) {
+ case WAKE_LOCK_PROXIMITY_POSITIVE:
+ return acquireProxPositiveSuspendBlocker();
+ case WAKE_LOCK_PROXIMITY_NEGATIVE:
+ return acquireProxNegativeSuspendBlocker();
+ case WAKE_LOCK_PROXIMITY_DEBOUNCE:
+ return acquireProxDebounceSuspendBlocker();
+ case WAKE_LOCK_STATE_CHANGED:
+ return acquireStateChangedSuspendBlocker();
+ case WAKE_LOCK_UNFINISHED_BUSINESS:
+ return acquireUnfinishedBusinessSuspendBlocker();
+ default:
+ throw new RuntimeException("Invalid wakelock attempted to be acquired");
+ }
+ }
+
+ private boolean releaseWakelockInternal(@WAKE_LOCK_TYPE int wakelock) {
+ switch (wakelock) {
+ case WAKE_LOCK_PROXIMITY_POSITIVE:
+ return releaseProxPositiveSuspendBlocker();
+ case WAKE_LOCK_PROXIMITY_NEGATIVE:
+ return releaseProxNegativeSuspendBlocker();
+ case WAKE_LOCK_PROXIMITY_DEBOUNCE:
+ return releaseProxDebounceSuspendBlocker();
+ case WAKE_LOCK_STATE_CHANGED:
+ return releaseStateChangedSuspendBlocker();
+ case WAKE_LOCK_UNFINISHED_BUSINESS:
+ return releaseUnfinishedBusinessSuspendBlocker();
+ default:
+ throw new RuntimeException("Invalid wakelock attempted to be released");
+ }
+ }
+
+ /**
+ * Acquires the proximity positive wakelock and notifies the PowerManagerService about the
+ * changes.
+ */
+ private boolean acquireProxPositiveSuspendBlocker() {
+ if (!mIsProximityPositiveAcquired) {
+ mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxPositive);
+ mIsProximityPositiveAcquired = true;
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Acquires the state change wakelock and notifies the PowerManagerService about the changes.
*/
- public boolean acquireStateChangedSuspendBlocker() {
+ private boolean acquireStateChangedSuspendBlocker() {
// Grab a wake lock if we have change of the display state
if (!mOnStateChangedPending) {
if (DEBUG) {
@@ -105,18 +203,20 @@
/**
* Releases the state change wakelock and notifies the PowerManagerService about the changes.
*/
- public void releaseStateChangedSuspendBlocker() {
+ private boolean releaseStateChangedSuspendBlocker() {
if (mOnStateChangedPending) {
mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged);
mOnStateChangedPending = false;
+ return true;
}
+ return false;
}
/**
* Acquires the unfinished business wakelock and notifies the PowerManagerService about the
* changes.
*/
- public void acquireUnfinishedBusinessSuspendBlocker() {
+ private boolean acquireUnfinishedBusinessSuspendBlocker() {
// Grab a wake lock if we have unfinished business.
if (!mUnfinishedBusiness) {
if (DEBUG) {
@@ -124,79 +224,84 @@
}
mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdUnfinishedBusiness);
mUnfinishedBusiness = true;
+ return true;
}
+ return false;
}
/**
* Releases the unfinished business wakelock and notifies the PowerManagerService about the
* changes.
*/
- public void releaseUnfinishedBusinessSuspendBlocker() {
+ private boolean releaseUnfinishedBusinessSuspendBlocker() {
if (mUnfinishedBusiness) {
if (DEBUG) {
Slog.d(mTag, "Finished business...");
}
mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdUnfinishedBusiness);
mUnfinishedBusiness = false;
+ return true;
}
- }
-
- /**
- * Acquires the proximity positive wakelock and notifies the PowerManagerService about the
- * changes.
- */
- public void acquireProxPositiveSuspendBlocker() {
- mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxPositive);
- mOnProximityPositiveMessages++;
+ return false;
}
/**
* Releases the proximity positive wakelock and notifies the PowerManagerService about the
* changes.
*/
- public void releaseProxPositiveSuspendBlocker() {
- for (int i = 0; i < mOnProximityPositiveMessages; i++) {
+ private boolean releaseProxPositiveSuspendBlocker() {
+ if (mIsProximityPositiveAcquired) {
mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive);
+ mIsProximityPositiveAcquired = false;
+ return true;
}
- mOnProximityPositiveMessages = 0;
+ return false;
}
/**
* Acquires the proximity negative wakelock and notifies the PowerManagerService about the
* changes.
*/
- public void acquireProxNegativeSuspendBlocker() {
- mOnProximityNegativeMessages++;
- mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxNegative);
+ private boolean acquireProxNegativeSuspendBlocker() {
+ if (!mIsProximityNegativeAcquired) {
+ mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxNegative);
+ mIsProximityNegativeAcquired = true;
+ return true;
+ }
+ return false;
}
/**
* Releases the proximity negative wakelock and notifies the PowerManagerService about the
* changes.
*/
- public void releaseProxNegativeSuspendBlocker() {
- for (int i = 0; i < mOnProximityNegativeMessages; i++) {
+ private boolean releaseProxNegativeSuspendBlocker() {
+ if (mIsProximityNegativeAcquired) {
mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative);
+ mIsProximityNegativeAcquired = false;
+ return true;
}
- mOnProximityNegativeMessages = 0;
+ return false;
}
/**
* Acquires the proximity debounce wakelock and notifies the PowerManagerService about the
* changes.
*/
- public void acquireProxDebounceSuspendBlocker() {
+ private boolean acquireProxDebounceSuspendBlocker() {
if (!mHasProximityDebounced) {
mDisplayPowerCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxDebounce);
+ mHasProximityDebounced = true;
+ return true;
}
- mHasProximityDebounced = true;
+ return false;
}
/**
* Releases the proximity debounce wakelock and notifies the PowerManagerService about the
* changes.
*/
- public boolean releaseProxDebounceSuspendBlocker() {
+ private boolean releaseProxDebounceSuspendBlocker() {
if (mHasProximityDebounced) {
mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxDebounce);
mHasProximityDebounced = false;
@@ -210,9 +315,11 @@
*/
public Runnable getOnProximityPositiveRunnable() {
return () -> {
- mOnProximityPositiveMessages--;
- mDisplayPowerCallbacks.onProximityPositive();
- mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive);
+ if (mIsProximityPositiveAcquired) {
+ mIsProximityPositiveAcquired = false;
+ mDisplayPowerCallbacks.onProximityPositive();
+ mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive);
+ }
};
}
@@ -221,9 +328,11 @@
*/
public Runnable getOnStateChangedRunnable() {
return () -> {
- mOnStateChangedPending = false;
- mDisplayPowerCallbacks.onStateChanged();
- mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged);
+ if (mOnStateChangedPending) {
+ mOnStateChangedPending = false;
+ mDisplayPowerCallbacks.onStateChanged();
+ mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged);
+ }
};
}
@@ -232,9 +341,11 @@
*/
public Runnable getOnProximityNegativeRunnable() {
return () -> {
- mOnProximityNegativeMessages--;
- mDisplayPowerCallbacks.onProximityNegative();
- mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative);
+ if (mIsProximityNegativeAcquired) {
+ mIsProximityNegativeAcquired = false;
+ mDisplayPowerCallbacks.onProximityNegative();
+ mDisplayPowerCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative);
+ }
};
}
@@ -246,8 +357,8 @@
pw.println(" mDisplayId=" + mDisplayId);
pw.println(" mUnfinishedBusiness=" + hasUnfinishedBusiness());
pw.println(" mOnStateChangePending=" + isOnStateChangedPending());
- pw.println(" mOnProximityPositiveMessages=" + getOnProximityPositiveMessages());
- pw.println(" mOnProximityNegativeMessages=" + getOnProximityNegativeMessages());
+ pw.println(" mOnProximityPositiveMessages=" + isProximityPositiveAcquired());
+ pw.println(" mOnProximityNegativeMessages=" + isProximityNegativeAcquired());
}
@VisibleForTesting
@@ -286,13 +397,13 @@
}
@VisibleForTesting
- int getOnProximityPositiveMessages() {
- return mOnProximityPositiveMessages;
+ boolean isProximityPositiveAcquired() {
+ return mIsProximityPositiveAcquired;
}
@VisibleForTesting
- int getOnProximityNegativeMessages() {
- return mOnProximityNegativeMessages;
+ boolean isProximityNegativeAcquired() {
+ return mIsProximityNegativeAcquired;
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index be3a4da..6b31555 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -54,6 +54,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.server.SystemConfig;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
@@ -1005,11 +1006,14 @@
/** @see ApplicationInfo#privateFlagsExt */
public static int appInfoPrivateFlagsExt(AndroidPackage pkg,
@Nullable PackageStateInternal pkgSetting) {
+ var isAllowlistedForHiddenApis = SystemConfig.getInstance().getHiddenApiWhitelistedApps()
+ .contains(pkg.getPackageName());
// @formatter:off
int pkgWithoutStateFlags = flag(pkg.isProfileable(), ApplicationInfo.PRIVATE_FLAG_EXT_PROFILEABLE)
| flag(pkg.hasRequestForegroundServiceExemption(), ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION)
| flag(pkg.areAttributionsUserVisible(), ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE)
- | flag(pkg.isOnBackInvokedCallbackEnabled(), ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK);
+ | flag(pkg.isOnBackInvokedCallbackEnabled(), ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK)
+ | flag(isAllowlistedForHiddenApis, ApplicationInfo.PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS);
return appInfoPrivateFlagsExt(pkgWithoutStateFlags, pkgSetting);
// @formatter:on
}
diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java
index cb52e5f..6e82907 100644
--- a/services/java/com/android/server/SystemConfigService.java
+++ b/services/java/com/android/server/SystemConfigService.java
@@ -101,6 +101,13 @@
}
return enabledComponent;
}
+
+ @Override
+ public List<ComponentName> getDefaultVrComponents() {
+ getContext().enforceCallingOrSelfPermission(Manifest.permission.QUERY_ALL_PACKAGES,
+ "Caller must hold " + Manifest.permission.QUERY_ALL_PACKAGES);
+ return new ArrayList<>(SystemConfig.getInstance().getDefaultVrComponents());
+ }
};
public SystemConfigService(Context context) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index 2df6823a..20af02e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -177,15 +177,19 @@
advanceTime(1);
// two times, one for unfinished business and one for proximity
- verify(mWakelockController).acquireUnfinishedBusinessSuspendBlocker();
- verify(mWakelockController).acquireProxDebounceSuspendBlocker();
+ verify(mWakelockController).acquireWakelock(
+ WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
+ verify(mWakelockController).acquireWakelock(
+ WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
dpc.stop();
advanceTime(1);
// two times, one for unfinished business and one for proximity
- verify(mWakelockController).acquireUnfinishedBusinessSuspendBlocker();
- verify(mWakelockController).acquireProxDebounceSuspendBlocker();
+ verify(mWakelockController).acquireWakelock(
+ WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
+ verify(mWakelockController).acquireWakelock(
+ WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE);
}
/**
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/WakelockControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/WakelockControllerTest.java
index 288408c..07a81ff 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/WakelockControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/WakelockControllerTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import android.hardware.display.DisplayManagerInternal;
@@ -33,6 +34,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.concurrent.Callable;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class WakelockControllerTest {
@@ -64,25 +67,18 @@
}
@Test
- public void acquireStateChangedSuspendBlockerAcquiresIfNotAcquired() {
- // Acquire the suspend blocker
- assertTrue(mWakelockController.acquireStateChangedSuspendBlocker());
- assertTrue(mWakelockController.isOnStateChangedPending());
-
- // Try to reacquire
- assertFalse(mWakelockController.acquireStateChangedSuspendBlocker());
- assertTrue(mWakelockController.isOnStateChangedPending());
+ public void acquireStateChangedSuspendBlockerAcquiresIfNotAcquired() throws Exception {
+ // Acquire
+ verifyWakelockAcquisitionAndReaquisition(WakelockController.WAKE_LOCK_STATE_CHANGED,
+ () -> mWakelockController.isOnStateChangedPending());
// Verify acquire happened only once
verify(mDisplayPowerCallbacks, times(1))
.acquireSuspendBlocker(mWakelockController.getSuspendBlockerOnStateChangedId());
// Release
- mWakelockController.releaseStateChangedSuspendBlocker();
- assertFalse(mWakelockController.isOnStateChangedPending());
-
- // Try to release again
- mWakelockController.releaseStateChangedSuspendBlocker();
+ verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_STATE_CHANGED,
+ () -> mWakelockController.isOnStateChangedPending());
// Verify release happened only once
verify(mDisplayPowerCallbacks, times(1))
@@ -90,25 +86,18 @@
}
@Test
- public void acquireUnfinishedBusinessSuspendBlockerAcquiresIfNotAcquired() {
- // Acquire the suspend blocker
- mWakelockController.acquireUnfinishedBusinessSuspendBlocker();
- assertTrue(mWakelockController.hasUnfinishedBusiness());
-
- // Try to reacquire
- mWakelockController.acquireUnfinishedBusinessSuspendBlocker();
- assertTrue(mWakelockController.hasUnfinishedBusiness());
+ public void acquireUnfinishedBusinessSuspendBlockerAcquiresIfNotAcquired() throws Exception {
+ // Acquire
+ verifyWakelockAcquisitionAndReaquisition(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS,
+ () -> mWakelockController.hasUnfinishedBusiness());
// Verify acquire happened only once
verify(mDisplayPowerCallbacks, times(1))
.acquireSuspendBlocker(mWakelockController.getSuspendBlockerUnfinishedBusinessId());
- // Release the suspend blocker
- mWakelockController.releaseUnfinishedBusinessSuspendBlocker();
- assertFalse(mWakelockController.hasUnfinishedBusiness());
-
- // Try to release again
- mWakelockController.releaseUnfinishedBusinessSuspendBlocker();
+ // Release
+ verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS,
+ () -> mWakelockController.hasUnfinishedBusiness());
// Verify release happened only once
verify(mDisplayPowerCallbacks, times(1))
@@ -116,70 +105,56 @@
}
@Test
- public void acquireProxPositiveSuspendBlockerAcquiresIfNotAcquired() {
- // Acquire the suspend blocker
- mWakelockController.acquireProxPositiveSuspendBlocker();
- assertEquals(mWakelockController.getOnProximityPositiveMessages(), 1);
-
- // Try to reacquire
- mWakelockController.acquireProxPositiveSuspendBlocker();
- assertEquals(mWakelockController.getOnProximityPositiveMessages(), 2);
+ public void acquireProxPositiveSuspendBlockerAcquiresIfNotAcquired() throws Exception {
+ // Acquire
+ verifyWakelockAcquisitionAndReaquisition(WakelockController.WAKE_LOCK_PROXIMITY_POSITIVE,
+ () -> mWakelockController.isProximityPositiveAcquired());
// Verify acquire happened only once
- verify(mDisplayPowerCallbacks, times(2))
+ verify(mDisplayPowerCallbacks, times(1))
.acquireSuspendBlocker(mWakelockController.getSuspendBlockerProxPositiveId());
- // Release the suspend blocker
- mWakelockController.releaseProxPositiveSuspendBlocker();
- assertEquals(mWakelockController.getOnProximityPositiveMessages(), 0);
+ // Release
+ verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_PROXIMITY_POSITIVE,
+ () -> mWakelockController.isProximityPositiveAcquired());
- // Verify all suspend blockers were released
- verify(mDisplayPowerCallbacks, times(2))
+ // Verify release happened only once
+ verify(mDisplayPowerCallbacks, times(1))
.releaseSuspendBlocker(mWakelockController.getSuspendBlockerProxPositiveId());
}
@Test
- public void acquireProxNegativeSuspendBlockerAcquiresIfNotAcquired() {
- // Acquire the suspend blocker
- mWakelockController.acquireProxNegativeSuspendBlocker();
- assertEquals(mWakelockController.getOnProximityNegativeMessages(), 1);
-
- // Try to reacquire
- mWakelockController.acquireProxNegativeSuspendBlocker();
- assertEquals(mWakelockController.getOnProximityNegativeMessages(), 2);
+ public void acquireProxNegativeSuspendBlockerAcquiresIfNotAcquired() throws Exception {
+ // Acquire
+ verifyWakelockAcquisitionAndReaquisition(WakelockController.WAKE_LOCK_PROXIMITY_NEGATIVE,
+ () -> mWakelockController.isProximityNegativeAcquired());
// Verify acquire happened only once
- verify(mDisplayPowerCallbacks, times(2))
+ verify(mDisplayPowerCallbacks, times(1))
.acquireSuspendBlocker(mWakelockController.getSuspendBlockerProxNegativeId());
- // Release the suspend blocker
- mWakelockController.releaseProxNegativeSuspendBlocker();
- assertEquals(mWakelockController.getOnProximityNegativeMessages(), 0);
+ // Release
+ verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_PROXIMITY_NEGATIVE,
+ () -> mWakelockController.isProximityNegativeAcquired());
- // Verify all suspend blockers were released
- verify(mDisplayPowerCallbacks, times(2))
+ // Verify release happened only once
+ verify(mDisplayPowerCallbacks, times(1))
.releaseSuspendBlocker(mWakelockController.getSuspendBlockerProxNegativeId());
}
@Test
- public void acquireProxDebounceSuspendBlockerAcquiresIfNotAcquired() {
+ public void acquireProxDebounceSuspendBlockerAcquiresIfNotAcquired() throws Exception {
// Acquire the suspend blocker
- mWakelockController.acquireProxDebounceSuspendBlocker();
-
- // Try to reacquire
- mWakelockController.acquireProxDebounceSuspendBlocker();
- assertTrue(mWakelockController.hasProximitySensorDebounced());
+ verifyWakelockAcquisitionAndReaquisition(WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE,
+ () -> mWakelockController.hasProximitySensorDebounced());
// Verify acquire happened only once
verify(mDisplayPowerCallbacks, times(1))
.acquireSuspendBlocker(mWakelockController.getSuspendBlockerProxDebounceId());
// Release the suspend blocker
- assertTrue(mWakelockController.releaseProxDebounceSuspendBlocker());
-
- // Release again
- assertFalse(mWakelockController.releaseProxDebounceSuspendBlocker());
- assertFalse(mWakelockController.hasProximitySensorDebounced());
+ verifyWakelockReleaseAndRerelease(WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE,
+ () -> mWakelockController.hasProximitySensorDebounced());
// Verify suspend blocker was released only once
verify(mDisplayPowerCallbacks, times(1))
@@ -189,52 +164,126 @@
@Test
public void proximityPositiveRunnableWorksAsExpected() {
// Acquire the suspend blocker twice
- mWakelockController.acquireProxPositiveSuspendBlocker();
- mWakelockController.acquireProxPositiveSuspendBlocker();
+ assertTrue(mWakelockController.acquireWakelock(
+ WakelockController.WAKE_LOCK_PROXIMITY_POSITIVE));
// Execute the runnable
Runnable proximityPositiveRunnable = mWakelockController.getOnProximityPositiveRunnable();
proximityPositiveRunnable.run();
// Validate one suspend blocker was released
- assertEquals(mWakelockController.getOnProximityPositiveMessages(), 1);
+ assertFalse(mWakelockController.isProximityPositiveAcquired());
verify(mDisplayPowerCallbacks).onProximityPositive();
verify(mDisplayPowerCallbacks).releaseSuspendBlocker(
mWakelockController.getSuspendBlockerProxPositiveId());
}
@Test
+ public void proximityPositiveRunnableDoesNothingIfNotAcquired() {
+ // Execute the runnable
+ Runnable proximityPositiveRunnable = mWakelockController.getOnProximityPositiveRunnable();
+ proximityPositiveRunnable.run();
+
+ // Validate one suspend blocker was released
+ assertFalse(mWakelockController.isProximityPositiveAcquired());
+ verifyZeroInteractions(mDisplayPowerCallbacks);
+ }
+
+ @Test
public void proximityNegativeRunnableWorksAsExpected() {
// Acquire the suspend blocker twice
- mWakelockController.acquireProxNegativeSuspendBlocker();
- mWakelockController.acquireProxNegativeSuspendBlocker();
+ assertTrue(mWakelockController.acquireWakelock(
+ WakelockController.WAKE_LOCK_PROXIMITY_NEGATIVE));
// Execute the runnable
Runnable proximityNegativeRunnable = mWakelockController.getOnProximityNegativeRunnable();
proximityNegativeRunnable.run();
// Validate one suspend blocker was released
- assertEquals(mWakelockController.getOnProximityNegativeMessages(), 1);
+ assertFalse(mWakelockController.isProximityNegativeAcquired());
verify(mDisplayPowerCallbacks).onProximityNegative();
verify(mDisplayPowerCallbacks).releaseSuspendBlocker(
mWakelockController.getSuspendBlockerProxNegativeId());
}
@Test
+ public void proximityNegativeRunnableDoesNothingIfNotAcquired() {
+ // Execute the runnable
+ Runnable proximityNegativeRunnable = mWakelockController.getOnProximityNegativeRunnable();
+ proximityNegativeRunnable.run();
+
+ // Validate one suspend blocker was released
+ assertFalse(mWakelockController.isProximityNegativeAcquired());
+ verifyZeroInteractions(mDisplayPowerCallbacks);
+ }
+
+ @Test
public void onStateChangeRunnableWorksAsExpected() {
// Acquire the suspend blocker twice
- mWakelockController.acquireStateChangedSuspendBlocker();
+ assertTrue(mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_STATE_CHANGED));
// Execute the runnable
Runnable stateChangeRunnable = mWakelockController.getOnStateChangedRunnable();
stateChangeRunnable.run();
// Validate one suspend blocker was released
- assertEquals(mWakelockController.isOnStateChangedPending(), false);
+ assertFalse(mWakelockController.isOnStateChangedPending());
verify(mDisplayPowerCallbacks).onStateChanged();
verify(mDisplayPowerCallbacks).releaseSuspendBlocker(
mWakelockController.getSuspendBlockerOnStateChangedId());
}
+ @Test
+ public void onStateChangeRunnableDoesNothingIfNotAcquired() {
+ // Execute the runnable
+ Runnable stateChangeRunnable = mWakelockController.getOnStateChangedRunnable();
+ stateChangeRunnable.run();
+
+ // Validate one suspend blocker was released
+ assertFalse(mWakelockController.isOnStateChangedPending());
+ verifyZeroInteractions(mDisplayPowerCallbacks);
+ }
+
+ private void verifyWakelockAcquisitionAndReaquisition(int wakelockId,
+ Callable<Boolean> isWakelockAcquiredCallable)
+ throws Exception {
+ verifyWakelockAcquisition(wakelockId, isWakelockAcquiredCallable);
+ verifyWakelockReacquisition(wakelockId, isWakelockAcquiredCallable);
+ }
+
+ private void verifyWakelockReleaseAndRerelease(int wakelockId,
+ Callable<Boolean> isWakelockAcquiredCallable)
+ throws Exception {
+ verifyWakelockRelease(wakelockId, isWakelockAcquiredCallable);
+ verifyWakelockRerelease(wakelockId, isWakelockAcquiredCallable);
+ }
+
+ private void verifyWakelockAcquisition(int wakelockId,
+ Callable<Boolean> isWakelockAcquiredCallable)
+ throws Exception {
+ assertTrue(mWakelockController.acquireWakelock(wakelockId));
+ assertTrue(isWakelockAcquiredCallable.call());
+ }
+
+ private void verifyWakelockReacquisition(int wakelockId,
+ Callable<Boolean> isWakelockAcquiredCallable)
+ throws Exception {
+ assertFalse(mWakelockController.acquireWakelock(wakelockId));
+ assertTrue(isWakelockAcquiredCallable.call());
+ }
+
+ private void verifyWakelockRelease(int wakelockId, Callable<Boolean> isWakelockAcquiredCallable)
+ throws Exception {
+ assertTrue(mWakelockController.releaseWakelock(wakelockId));
+ assertFalse(isWakelockAcquiredCallable.call());
+ }
+
+ private void verifyWakelockRerelease(int wakelockId,
+ Callable<Boolean> isWakelockAcquiredCallable)
+ throws Exception {
+ assertFalse(mWakelockController.releaseWakelock(wakelockId));
+ assertFalse(isWakelockAcquiredCallable.call());
+ }
+
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index cc57b9f..dc7bcd6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -38,6 +38,7 @@
import android.os.incremental.IncrementalManager
import android.provider.DeviceConfig
import android.util.ArrayMap
+import android.util.ArraySet
import android.util.DisplayMetrics
import android.util.EventLog
import android.view.Display
@@ -294,6 +295,8 @@
wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig)
whenever(mocks.systemConfig.availableFeatures).thenReturn(DEFAULT_AVAILABLE_FEATURES_MAP)
whenever(mocks.systemConfig.sharedLibraries).thenReturn(DEFAULT_SHARED_LIBRARIES_LIST)
+ whenever(mocks.systemConfig.defaultVrComponents).thenReturn(ArraySet())
+ whenever(mocks.systemConfig.hiddenApiWhitelistedApps).thenReturn(ArraySet())
wheneverStatic { SystemProperties.getBoolean("fw.free_cache_v2", true) }.thenReturn(true)
wheneverStatic { Environment.getPackageCacheDirectory() }.thenReturn(packageCacheDirectory)
wheneverStatic { SystemProperties.digestOf("ro.build.fingerprint") }.thenReturn("cacheName")
diff --git a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
index bccd8a0b..9ae8922 100644
--- a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -61,6 +62,7 @@
public class UserBackupManagerServiceTest {
private static final String TEST_PACKAGE = "package1";
private static final String[] TEST_PACKAGES = new String[] { TEST_PACKAGE };
+ private static final int WORKER_THREAD_TIMEOUT_MILLISECONDS = 1;
@Mock Context mContext;
@Mock IBackupManagerMonitor mBackupManagerMonitor;
@@ -179,6 +181,7 @@
mService.agentDisconnected("com.android.foo");
+ mService.waitForAsyncOperation();
verify(mOperationStorage).cancelOperation(eq(123), eq(true), any(IntConsumer.class));
verify(mOperationStorage).cancelOperation(eq(456), eq(true), any());
verify(mOperationStorage).cancelOperation(eq(789), eq(true), any());
@@ -207,6 +210,8 @@
boolean isEnabledStatePersisted = false;
boolean shouldUseNewBackupEligibilityRules = false;
+ private volatile Thread mWorkerThread = null;
+
TestBackupService(Context context, PackageManager packageManager,
LifecycleOperationStorage operationStorage) {
super(context, packageManager, operationStorage);
@@ -229,5 +234,23 @@
boolean shouldUseNewBackupEligibilityRules() {
return shouldUseNewBackupEligibilityRules;
}
+
+ @Override
+ Thread getThreadForAsyncOperation(String operationName, Runnable operation) {
+ mWorkerThread = super.getThreadForAsyncOperation(operationName, operation);
+ return mWorkerThread;
+ }
+
+ private void waitForAsyncOperation() {
+ if (mWorkerThread == null) {
+ return;
+ }
+
+ try {
+ mWorkerThread.join(/* millis */ WORKER_THREAD_TIMEOUT_MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("Failed waiting for worker thread to complete: " + e.getMessage());
+ }
+ }
}
}
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 79ab009..5179bab 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -27,7 +27,6 @@
import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.SystemProperties;
-import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import java.io.PrintWriter;
@@ -195,57 +194,20 @@
}
/**
- * Convert display name source to string.
+ * Convert mobile data policy to string.
*
- * @param source The display name source.
- * @return The display name source in string format.
+ * @param mobileDataPolicy The mobile data policy.
+ * @return The mobile data policy in string format.
*/
- @NonNull
- public static String displayNameSourceToString(
- @SubscriptionManager.SimDisplayNameSource int source) {
- switch (source) {
- case SubscriptionManager.NAME_SOURCE_UNKNOWN: return "UNKNOWN";
- case SubscriptionManager.NAME_SOURCE_CARRIER_ID: return "CARRIER_ID";
- case SubscriptionManager.NAME_SOURCE_SIM_SPN: return "SIM_SPN";
- case SubscriptionManager.NAME_SOURCE_USER_INPUT: return "USER_INPUT";
- case SubscriptionManager.NAME_SOURCE_CARRIER: return "CARRIER";
- case SubscriptionManager.NAME_SOURCE_SIM_PNN: return "SIM_PNN";
+ public static @NonNull String mobileDataPolicyToString(
+ @TelephonyManager.MobileDataPolicy int mobileDataPolicy) {
+ switch (mobileDataPolicy) {
+ case TelephonyManager.MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL:
+ return "DATA_ON_NON_DEFAULT_DURING_VOICE_CALL";
+ case TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED:
+ return "MMS_ALWAYS_ALLOWED";
default:
- return "UNKNOWN(" + source + ")";
- }
- }
-
- /**
- * Convert subscription type to string.
- *
- * @param type The subscription type.
- * @return The subscription type in string format.
- */
- @NonNull
- public static String subscriptionTypeToString(@SubscriptionManager.SubscriptionType int type) {
- switch (type) {
- case SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM: return "LOCAL_SIM";
- case SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM: return "REMOTE_SIM";
- default:
- return "UNKNOWN(" + type + ")";
- }
- }
-
- /**
- * Convert usage setting to string.
- *
- * @param usageSetting Usage setting.
- * @return The usage setting in string format.
- */
- @NonNull
- public static String usageSettingToString(@SubscriptionManager.UsageSetting int usageSetting) {
- switch (usageSetting) {
- case SubscriptionManager.USAGE_SETTING_UNKNOWN: return "UNKNOWN";
- case SubscriptionManager.USAGE_SETTING_DEFAULT: return "DEFAULT";
- case SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC: return "VOICE_CENTRIC";
- case SubscriptionManager.USAGE_SETTING_DATA_CENTRIC: return "DATA_CENTRIC";
- default:
- return "UNKNOWN(" + usageSetting + ")";
+ return "UNKNOWN(" + mobileDataPolicy + ")";
}
}
}
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 0d3c80f..e055f63 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -974,7 +974,7 @@
+ " groupOwner=" + mGroupOwner
+ " isGroupDisabled=" + mIsGroupDisabled
+ " displayNameSource="
- + TelephonyUtils.displayNameSourceToString(mDisplayNameSource)
+ + SubscriptionManager.displayNameSourceToString(mDisplayNameSource)
+ " iconTint=" + mIconTint
+ " number=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumber)
+ " dataRoaming=" + mDataRoaming
@@ -988,9 +988,9 @@
+ " carrierConfigAccessRules=" + Arrays.toString(mCarrierConfigAccessRules)
+ " countryIso=" + mCountryIso
+ " profileClass=" + mProfileClass
- + " mType=" + TelephonyUtils.subscriptionTypeToString(mType)
+ + " mType=" + SubscriptionManager.subscriptionTypeToString(mType)
+ " areUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled
- + " usageSetting=" + TelephonyUtils.usageSettingToString(mUsageSetting)
+ + " usageSetting=" + SubscriptionManager.usageSettingToString(mUsageSetting)
+ "]";
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 6189b49..e6c6b62 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -4092,4 +4092,65 @@
(iSub)-> iSub.setUsageSetting(
usageSetting, subscriptionId, mContext.getOpPackageName()));
}
+
+ /**
+ * Convert display name source to string.
+ *
+ * @param source The display name source.
+ * @return The display name source in string format.
+ *
+ * @hide
+ */
+ @NonNull
+ public static String displayNameSourceToString(
+ @SubscriptionManager.SimDisplayNameSource int source) {
+ switch (source) {
+ case SubscriptionManager.NAME_SOURCE_UNKNOWN: return "UNKNOWN";
+ case SubscriptionManager.NAME_SOURCE_CARRIER_ID: return "CARRIER_ID";
+ case SubscriptionManager.NAME_SOURCE_SIM_SPN: return "SIM_SPN";
+ case SubscriptionManager.NAME_SOURCE_USER_INPUT: return "USER_INPUT";
+ case SubscriptionManager.NAME_SOURCE_CARRIER: return "CARRIER";
+ case SubscriptionManager.NAME_SOURCE_SIM_PNN: return "SIM_PNN";
+ default:
+ return "UNKNOWN(" + source + ")";
+ }
+ }
+
+ /**
+ * Convert subscription type to string.
+ *
+ * @param type The subscription type.
+ * @return The subscription type in string format.
+ *
+ * @hide
+ */
+ @NonNull
+ public static String subscriptionTypeToString(@SubscriptionManager.SubscriptionType int type) {
+ switch (type) {
+ case SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM: return "LOCAL_SIM";
+ case SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM: return "REMOTE_SIM";
+ default:
+ return "UNKNOWN(" + type + ")";
+ }
+ }
+
+ /**
+ * Convert usage setting to string.
+ *
+ * @param usageSetting Usage setting.
+ * @return The usage setting in string format.
+ *
+ * @hide
+ */
+ @NonNull
+ public static String usageSettingToString(@SubscriptionManager.UsageSetting int usageSetting) {
+ switch (usageSetting) {
+ case SubscriptionManager.USAGE_SETTING_UNKNOWN: return "UNKNOWN";
+ case SubscriptionManager.USAGE_SETTING_DEFAULT: return "DEFAULT";
+ case SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC: return "VOICE_CENTRIC";
+ case SubscriptionManager.USAGE_SETTING_DATA_CENTRIC: return "DATA_CENTRIC";
+ default:
+ return "UNKNOWN(" + usageSetting + ")";
+ }
+ }
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index e658c2e..caee4e2 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -72,6 +72,7 @@
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "WIFI_MODE_", value = {
+ WIFI_MODE_UNKNOWN,
WIFI_MODE_WIFI_ONLY,
WIFI_MODE_CELLULAR_PREFERRED,
WIFI_MODE_WIFI_PREFERRED
@@ -79,6 +80,12 @@
public @interface WiFiCallingMode {}
/**
+ * Wifi calling mode is unknown. This is for initialization only.
+ * @hide
+ */
+ public static final int WIFI_MODE_UNKNOWN = -1;
+
+ /**
* Register for IMS over IWLAN if WiFi signal quality is high enough. Do not hand over to LTE
* registration if signal quality degrades.
*/
@@ -1573,4 +1580,24 @@
.get());
return binder;
}
+
+ /**
+ * Convert Wi-Fi calling mode to string.
+ *
+ * @param mode Wi-Fi calling mode.
+ * @return The Wi-Fi calling mode in string format.
+ *
+ * @hide
+ */
+ @NonNull
+ public static String wifiCallingModeToString(@ImsMmTelManager.WiFiCallingMode int mode) {
+ switch (mode) {
+ case ImsMmTelManager.WIFI_MODE_UNKNOWN: return "UNKNOWN";
+ case ImsMmTelManager.WIFI_MODE_WIFI_ONLY: return "WIFI_ONLY";
+ case ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED: return "CELLULAR_PREFERRED";
+ case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED: return "WIFI_PREFERRED";
+ default:
+ return "UNKNOWN(" + mode + ")";
+ }
+ }
}
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index 03eb462..d91aa1e 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -13,8 +13,6 @@
<option name="run-command" value="cmd window tracing level all" />
<!-- set WM tracing to frame (avoid incomplete states) -->
<option name="run-command" value="cmd window tracing frame" />
- <!-- set Layer tracing buffer size to 50mb -->
- <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 51200" />
<!-- ensure lock screen mode is swipe -->
<option name="run-command" value="locksettings set-disabled false" />
<!-- restart launcher to activate TAPL -->