Merge "TEST_MAPPING for FileIntegrityManager related files" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 525ae80..a5178cf 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -34,6 +34,7 @@
":android.view.inputmethod.flags-aconfig-java{.generated_srcjars}",
":android.widget.flags-aconfig-java{.generated_srcjars}",
":com.android.media.flags.bettertogether-aconfig-java{.generated_srcjars}",
+ ":sdk_sandbox_flags_lib{.generated_srcjars}",
],
// Add aconfig-annotations-lib as a dependency for the optimization
libs: ["aconfig-annotations-lib"],
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a366464..7bc6f9bf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -23,7 +23,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.inMultiWindowMode;
import static android.os.Process.myUid;
-
+import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext;
import static java.lang.Character.MIN_VALUE;
import android.annotation.AnimRes;
@@ -8631,6 +8631,12 @@
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
IBinder shareableActivityToken) {
+ if (sandboxActivitySdkBasedContext()) {
+ // Sandbox activities extract a token from the intent's extra to identify the related
+ // SDK as part of overriding attachBaseContext, then it wraps the passed context in an
+ // SDK ContextWrapper, so mIntent has to be set before calling attachBaseContext.
+ mIntent = intent;
+ }
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
@@ -8656,6 +8662,7 @@
mShareableActivityToken = shareableActivityToken;
mIdent = ident;
mApplication = application;
+ //TODO(b/300059435): do not set the mIntent again as part of the flag clean up.
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f28b4b4..00e546a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -38,6 +38,7 @@
import static android.window.ConfigurationHelper.shouldUpdateResources;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.os.SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL;
+import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -53,6 +54,8 @@
import android.app.backup.BackupAnnotations.BackupDestination;
import android.app.backup.BackupAnnotations.OperationType;
import android.app.compat.CompatChanges;
+import android.app.sdksandbox.sandboxactivity.ActivityContextInfo;
+import android.app.sdksandbox.sandboxactivity.ActivityContextInfoProvider;
import android.app.servertransaction.ActivityLifecycleItem;
import android.app.servertransaction.ActivityLifecycleItem.LifecycleState;
import android.app.servertransaction.ActivityRelaunchItem;
@@ -3655,15 +3658,16 @@
}
@UnsupportedAppUsage
- public final void sendActivityResult(
- IBinder token, String id, int requestCode,
+ public void sendActivityResult(
+ IBinder activityToken, String id, int requestCode,
int resultCode, Intent data) {
if (DEBUG_RESULTS) Slog.v(TAG, "sendActivityResult: id=" + id
+ " req=" + requestCode + " res=" + resultCode + " data=" + data);
ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
list.add(new ResultInfo(id, requestCode, resultCode, data));
- final ClientTransaction clientTransaction = ClientTransaction.obtain(mAppThread, token);
- clientTransaction.addCallback(ActivityResultItem.obtain(list));
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(mAppThread,
+ activityToken);
+ clientTransaction.addCallback(ActivityResultItem.obtain(activityToken, list));
try {
mAppThread.scheduleTransaction(clientTransaction);
} catch (RemoteException e) {
@@ -3733,16 +3737,38 @@
r.activityInfo.targetActivity);
}
- ContextImpl appContext = createBaseContextForActivity(r);
+ boolean isSandboxActivityContext = sandboxActivitySdkBasedContext()
+ && r.intent.isSandboxActivity(mSystemContext);
+ boolean isSandboxedSdkContextUsed = false;
+ ContextImpl activityBaseContext;
+ if (isSandboxActivityContext) {
+ activityBaseContext = createBaseContextForSandboxActivity(r);
+ if (activityBaseContext == null) {
+ // Failed to retrieve the SDK based sandbox activity context, falling back to the
+ // app based context.
+ activityBaseContext = createBaseContextForActivity(r);
+ } else {
+ isSandboxedSdkContextUsed = true;
+ }
+ } else {
+ activityBaseContext = createBaseContextForActivity(r);
+ }
Activity activity = null;
try {
- java.lang.ClassLoader cl = appContext.getClassLoader();
+ java.lang.ClassLoader cl;
+ if (isSandboxedSdkContextUsed) {
+ // In case of sandbox activity, the context refers to the an SDK with no visibility
+ // on the SandboxedActivity java class, the App context should be used instead.
+ cl = activityBaseContext.getApplicationContext().getClassLoader();
+ } else {
+ cl = activityBaseContext.getClassLoader();
+ }
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
- appContext.getAttributionSource());
+ activityBaseContext.getAttributionSource());
if (r.state != null) {
r.state.setClassLoader(cl);
}
@@ -3773,7 +3799,8 @@
}
if (activity != null) {
- CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
+ CharSequence title =
+ r.activityInfo.loadLabel(activityBaseContext.getPackageManager());
Configuration config =
new Configuration(mConfigurationController.getCompatConfiguration());
if (r.overrideConfig != null) {
@@ -3790,11 +3817,11 @@
// Activity resources must be initialized with the same loaders as the
// application context.
- appContext.getResources().addLoaders(
+ activityBaseContext.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
- appContext.setOuterContext(activity);
- activity.attach(appContext, this, getInstrumentation(), r.token,
+ activityBaseContext.setOuterContext(activity);
+ activity.attach(activityBaseContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
@@ -3951,6 +3978,44 @@
}
/**
+ * Creates the base context for the sandbox activity based on its corresponding SDK {@link
+ * ApplicationInfo} and flags.
+ */
+ @Nullable
+ private ContextImpl createBaseContextForSandboxActivity(@NonNull ActivityClientRecord r) {
+ ActivityContextInfoProvider contextInfoProvider = ActivityContextInfoProvider.getInstance();
+
+ ActivityContextInfo contextInfo;
+ try {
+ contextInfo = contextInfoProvider.getActivityContextInfo(r.intent);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Passed intent does not match an expected sandbox activity", e);
+ return null;
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "SDK customized context flag is disabled", e);
+ return null;
+ } catch (Exception e) { // generic catch to unexpected exceptions
+ Log.e(TAG, "Failed to create context for sandbox activity", e);
+ return null;
+ }
+
+ final int displayId = ActivityClient.getInstance().getDisplayId(r.token);
+ final LoadedApk sdkApk = getPackageInfo(
+ contextInfo.getSdkApplicationInfo(),
+ r.packageInfo.getCompatibilityInfo(),
+ ActivityContextInfo.CONTEXT_FLAGS);
+
+ final ContextImpl activityContext = ContextImpl.createActivityContext(
+ this, sdkApk, r.activityInfo, r.token, displayId, r.overrideConfig);
+
+ // Set sandbox app's context as the application context for sdk context
+ activityContext.mPackageInfo.makeApplicationInner(
+ /*forceDefaultAppClass=*/false, mInstrumentation);
+
+ return activityContext;
+ }
+
+ /**
* Extended implementation of activity launch. Used when server requests a launch or relaunch.
*/
@Override
@@ -4365,16 +4430,16 @@
private void schedulePauseWithUserLeavingHint(ActivityClientRecord r) {
final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token);
- transaction.setLifecycleStateRequest(PauseActivityItem.obtain(r.activity.isFinishing(),
- /* userLeaving */ true, r.activity.mConfigChangeFlags, /* dontReport */ false,
- /* autoEnteringPip */ false));
+ transaction.setLifecycleStateRequest(PauseActivityItem.obtain(r.token,
+ r.activity.isFinishing(), /* userLeaving */ true, r.activity.mConfigChangeFlags,
+ /* dontReport */ false, /* autoEnteringPip */ false));
executeTransaction(transaction);
}
private void scheduleResume(ActivityClientRecord r) {
final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token);
- transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(/* isForward */ false,
- /* shouldSendCompatFakeFocus */ false));
+ transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(r.token,
+ /* isForward */ false, /* shouldSendCompatFakeFocus */ false));
executeTransaction(transaction);
}
@@ -5958,8 +6023,8 @@
? r.createdConfig : mConfigurationController.getConfiguration(),
r.overrideConfig);
final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain(
- null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */,
- mergedConfiguration, r.mPreserveWindow);
+ r.token, null /* pendingResults */, null /* pendingIntents */,
+ 0 /* configChanges */, mergedConfiguration, r.mPreserveWindow);
// Make sure to match the existing lifecycle state in the end of the transaction.
final ActivityLifecycleItem lifecycleRequest =
TransactionExecutorHelper.getLifecycleRequestForCurrentState(r);
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index e409254..c2c5427 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -45,7 +45,7 @@
CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration);
// Notify the client of an upcoming change in the token configuration. This ensures that
// batches of config change items only process the newest configuration.
- client.updatePendingActivityConfiguration(token, mConfiguration);
+ client.updatePendingActivityConfiguration(getActivityToken(), mConfiguration);
}
@Override
@@ -61,8 +61,7 @@
@Override
public Context getContextToUpdate(@NonNull ClientTransactionHandler client,
@Nullable IBinder token) {
- // TODO(b/260873529): Update ClientTransaction to bundle multiple activity config updates.
- return client.getActivity(token);
+ return client.getActivity(getActivityToken());
}
// ObjectPoolItem implementation
@@ -70,7 +69,9 @@
private ActivityConfigurationChangeItem() {}
/** Obtain an instance initialized with provided params. */
- public static ActivityConfigurationChangeItem obtain(@NonNull Configuration config) {
+ @NonNull
+ public static ActivityConfigurationChangeItem obtain(@NonNull IBinder activityToken,
+ @NonNull Configuration config) {
if (config == null) {
throw new IllegalArgumentException("Config must not be null.");
}
@@ -80,6 +81,7 @@
if (instance == null) {
instance = new ActivityConfigurationChangeItem();
}
+ instance.setActivityToken(activityToken);
instance.mConfiguration = config;
return instance;
@@ -87,6 +89,7 @@
@Override
public void recycle() {
+ super.recycle();
mConfiguration = Configuration.EMPTY;
ObjectPool.recycle(this);
}
@@ -96,32 +99,34 @@
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeTypedObject(mConfiguration, flags);
}
/** Read from Parcel. */
- private ActivityConfigurationChangeItem(Parcel in) {
+ private ActivityConfigurationChangeItem(@NonNull Parcel in) {
+ super(in);
mConfiguration = in.readTypedObject(Configuration.CREATOR);
}
public static final @NonNull Creator<ActivityConfigurationChangeItem> CREATOR =
- new Creator<ActivityConfigurationChangeItem>() {
- public ActivityConfigurationChangeItem createFromParcel(Parcel in) {
- return new ActivityConfigurationChangeItem(in);
- }
+ new Creator<>() {
+ public ActivityConfigurationChangeItem createFromParcel(@NonNull Parcel in) {
+ return new ActivityConfigurationChangeItem(in);
+ }
- public ActivityConfigurationChangeItem[] newArray(int size) {
- return new ActivityConfigurationChangeItem[size];
- }
- };
+ public ActivityConfigurationChangeItem[] newArray(int size) {
+ return new ActivityConfigurationChangeItem[size];
+ }
+ };
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final ActivityConfigurationChangeItem other = (ActivityConfigurationChangeItem) o;
@@ -130,11 +135,15 @@
@Override
public int hashCode() {
- return mConfiguration.hashCode();
+ int result = 17;
+ result = 31 * result + super.hashCode();
+ result = 31 * result + Objects.hashCode(mConfiguration);
+ return result;
}
@Override
public String toString() {
- return "ActivityConfigurationChange{config=" + mConfiguration + "}";
+ return "ActivityConfigurationChange{" + super.toString()
+ + ",config=" + mConfiguration + "}";
}
}
diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
index cadb660..b34f678 100644
--- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java
+++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
@@ -17,6 +17,8 @@
package android.app.servertransaction;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -50,12 +52,13 @@
public static final int ON_DESTROY = 6;
public static final int ON_RESTART = 7;
+ ActivityLifecycleItem() {}
+
+ ActivityLifecycleItem(@NonNull Parcel in) {
+ super(in);
+ }
+
/** A final lifecycle state that an activity should reach. */
@LifecycleState
public abstract int getTargetState();
-
- /** Called by subclasses to make sure base implementation is cleaned up */
- @Override
- public void recycle() {
- }
}
diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
index a8b058a..491d026 100644
--- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java
+++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
@@ -56,18 +56,18 @@
private ActivityClientRecord mActivityClientRecord;
@Override
- public void preExecute(ClientTransactionHandler client, IBinder token) {
+ public void preExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token) {
// The local config is already scaled so only apply if this item is from server side.
if (!client.isExecutingLocalTransaction()) {
CompatibilityInfo.applyOverrideScaleIfNeeded(mConfig);
}
- mActivityClientRecord = client.prepareRelaunchActivity(token, mPendingResults,
+ mActivityClientRecord = client.prepareRelaunchActivity(getActivityToken(), mPendingResults,
mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow);
}
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
if (mActivityClientRecord == null) {
if (DEBUG_ORDER) Slog.d(TAG, "Activity relaunch cancelled");
return;
@@ -78,9 +78,9 @@
}
@Override
- public void postExecute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
- final ActivityClientRecord r = getActivityClientRecord(client, token);
+ public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token,
+ @NonNull PendingTransactionActions pendingActions) {
+ final ActivityClientRecord r = getActivityClientRecord(client);
client.reportRelaunch(r);
}
@@ -89,13 +89,16 @@
private ActivityRelaunchItem() {}
/** Obtain an instance initialized with provided params. */
- public static ActivityRelaunchItem obtain(List<ResultInfo> pendingResults,
- List<ReferrerIntent> pendingNewIntents, int configChanges, MergedConfiguration config,
- boolean preserveWindow) {
+ @NonNull
+ public static ActivityRelaunchItem obtain(@NonNull IBinder activityToken,
+ @Nullable List<ResultInfo> pendingResults,
+ @Nullable List<ReferrerIntent> pendingNewIntents, int configChanges,
+ @NonNull MergedConfiguration config, boolean preserveWindow) {
ActivityRelaunchItem instance = ObjectPool.obtain(ActivityRelaunchItem.class);
if (instance == null) {
instance = new ActivityRelaunchItem();
}
+ instance.setActivityToken(activityToken);
instance.mPendingResults = pendingResults;
instance.mPendingNewIntents = pendingNewIntents;
instance.mConfigChanges = configChanges;
@@ -107,6 +110,7 @@
@Override
public void recycle() {
+ super.recycle();
mPendingResults = null;
mPendingNewIntents = null;
mConfigChanges = 0;
@@ -121,7 +125,8 @@
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeTypedList(mPendingResults, flags);
dest.writeTypedList(mPendingNewIntents, flags);
dest.writeInt(mConfigChanges);
@@ -130,7 +135,8 @@
}
/** Read from Parcel. */
- private ActivityRelaunchItem(Parcel in) {
+ private ActivityRelaunchItem(@NonNull Parcel in) {
+ super(in);
mPendingResults = in.createTypedArrayList(ResultInfo.CREATOR);
mPendingNewIntents = in.createTypedArrayList(ReferrerIntent.CREATOR);
mConfigChanges = in.readInt();
@@ -139,22 +145,22 @@
}
public static final @NonNull Creator<ActivityRelaunchItem> CREATOR =
- new Creator<ActivityRelaunchItem>() {
- public ActivityRelaunchItem createFromParcel(Parcel in) {
- return new ActivityRelaunchItem(in);
- }
+ new Creator<>() {
+ public ActivityRelaunchItem createFromParcel(@NonNull Parcel in) {
+ return new ActivityRelaunchItem(in);
+ }
- public ActivityRelaunchItem[] newArray(int size) {
- return new ActivityRelaunchItem[size];
- }
- };
+ public ActivityRelaunchItem[] newArray(int size) {
+ return new ActivityRelaunchItem[size];
+ }
+ };
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final ActivityRelaunchItem other = (ActivityRelaunchItem) o;
@@ -167,6 +173,7 @@
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + super.hashCode();
result = 31 * result + Objects.hashCode(mPendingResults);
result = 31 * result + Objects.hashCode(mPendingNewIntents);
result = 31 * result + mConfigChanges;
@@ -177,8 +184,11 @@
@Override
public String toString() {
- return "ActivityRelaunchItem{pendingResults=" + mPendingResults
- + ",pendingNewIntents=" + mPendingNewIntents + ",configChanges=" + mConfigChanges
- + ",config=" + mConfig + ",preserveWindow" + mPreserveWindow + "}";
+ return "ActivityRelaunchItem{" + super.toString()
+ + ",pendingResults=" + mPendingResults
+ + ",pendingNewIntents=" + mPendingNewIntents
+ + ",configChanges=" + mConfigChanges
+ + ",config=" + mConfig
+ + ",preserveWindow" + mPreserveWindow + "}";
}
}
diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java
index 27d104b..24fced4 100644
--- a/core/java/android/app/servertransaction/ActivityResultItem.java
+++ b/core/java/android/app/servertransaction/ActivityResultItem.java
@@ -30,6 +30,7 @@
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Trace;
@@ -61,24 +62,26 @@
}
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult");
client.handleSendResult(r, mResultInfoList, "ACTIVITY_RESULT");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
-
// ObjectPoolItem implementation
private ActivityResultItem() {}
/** Obtain an instance initialized with provided params. */
- public static ActivityResultItem obtain(List<ResultInfo> resultInfoList) {
+ @NonNull
+ public static ActivityResultItem obtain(@NonNull IBinder activityToken,
+ @NonNull List<ResultInfo> resultInfoList) {
ActivityResultItem instance = ObjectPool.obtain(ActivityResultItem.class);
if (instance == null) {
instance = new ActivityResultItem();
}
+ instance.setActivityToken(activityToken);
instance.mResultInfoList = resultInfoList;
return instance;
@@ -86,41 +89,43 @@
@Override
public void recycle() {
+ super.recycle();
mResultInfoList = null;
ObjectPool.recycle(this);
}
-
// Parcelable implementation
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeTypedList(mResultInfoList, flags);
}
/** Read from Parcel. */
- private ActivityResultItem(Parcel in) {
+ private ActivityResultItem(@NonNull Parcel in) {
+ super(in);
mResultInfoList = in.createTypedArrayList(ResultInfo.CREATOR);
}
public static final @NonNull Parcelable.Creator<ActivityResultItem> CREATOR =
- new Parcelable.Creator<ActivityResultItem>() {
- public ActivityResultItem createFromParcel(Parcel in) {
- return new ActivityResultItem(in);
- }
+ new Parcelable.Creator<>() {
+ public ActivityResultItem createFromParcel(@NonNull Parcel in) {
+ return new ActivityResultItem(in);
+ }
- public ActivityResultItem[] newArray(int size) {
- return new ActivityResultItem[size];
- }
- };
+ public ActivityResultItem[] newArray(int size) {
+ return new ActivityResultItem[size];
+ }
+ };
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final ActivityResultItem other = (ActivityResultItem) o;
@@ -129,11 +134,15 @@
@Override
public int hashCode() {
- return mResultInfoList.hashCode();
+ int result = 17;
+ result = 31 * result + super.hashCode();
+ result = 31 * result + Objects.hashCode(mResultInfoList);
+ return result;
}
@Override
public String toString() {
- return "ActivityResultItem{resultInfoList=" + mResultInfoList + "}";
+ return "ActivityResultItem{" + super.toString()
+ + ",resultInfoList=" + mResultInfoList + "}";
}
}
diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java
index 469a9bf..0f8879e 100644
--- a/core/java/android/app/servertransaction/ActivityTransactionItem.java
+++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java
@@ -18,13 +18,18 @@
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import android.annotation.CallSuper;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.os.IBinder;
+import android.os.Parcel;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.Objects;
+
/**
* An activity-targeting callback message to a client that can be scheduled and executed.
* It also provides nullity-free version of
@@ -37,11 +42,16 @@
* @hide
*/
public abstract class ActivityTransactionItem extends ClientTransactionItem {
- @Override
- public final void execute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
- final ActivityClientRecord r = getActivityClientRecord(client, token);
+ /** Target client activity. */
+ private IBinder mActivityToken;
+
+ ActivityTransactionItem() {}
+
+ @Override
+ public final void execute(@NonNull ClientTransactionHandler client, @NonNull IBinder token,
+ @NonNull PendingTransactionActions pendingActions) {
+ final ActivityClientRecord r = getActivityClientRecord(client);
execute(client, r, pendingActions);
}
@@ -51,25 +61,80 @@
*/
@VisibleForTesting(visibility = PACKAGE)
public abstract void execute(@NonNull ClientTransactionHandler client,
- @NonNull ActivityClientRecord r, PendingTransactionActions pendingActions);
+ @NonNull ActivityClientRecord r, @NonNull PendingTransactionActions pendingActions);
/**
- * Gets the {@link ActivityClientRecord} instance that corresponds to the provided token.
+ * Gets the {@link ActivityClientRecord} instance that this transaction item is for.
* @param client Target client handler.
- * @param token Target activity token.
- * @return The {@link ActivityClientRecord} instance that corresponds to the provided token.
+ * @return The {@link ActivityClientRecord} instance that this transaction item is for.
*/
- @NonNull ActivityClientRecord getActivityClientRecord(
- @NonNull ClientTransactionHandler client, IBinder token) {
- final ActivityClientRecord r = client.getActivityClient(token);
+ @NonNull
+ final ActivityClientRecord getActivityClientRecord(@NonNull ClientTransactionHandler client) {
+ final ActivityClientRecord r = client.getActivityClient(getActivityToken());
if (r == null) {
throw new IllegalArgumentException("Activity client record must not be null to execute "
+ "transaction item: " + this);
}
- if (client.getActivity(token) == null) {
+ if (client.getActivity(getActivityToken()) == null) {
throw new IllegalArgumentException("Activity must not be null to execute "
+ "transaction item: " + this);
}
return r;
}
+
+ @VisibleForTesting(visibility = PACKAGE)
+ @NonNull
+ @Override
+ public IBinder getActivityToken() {
+ return mActivityToken;
+ }
+
+ void setActivityToken(@NonNull IBinder activityToken) {
+ mActivityToken = activityToken;
+ }
+
+ // To be overridden
+
+ ActivityTransactionItem(@NonNull Parcel in) {
+ mActivityToken = in.readStrongBinder();
+ }
+
+ @CallSuper
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStrongBinder(mActivityToken);
+ }
+
+ @CallSuper
+ @Override
+ public void recycle() {
+ mActivityToken = null;
+ }
+
+ // Subclass must override and call super.equals to compare the mActivityToken.
+ @SuppressWarnings("EqualsGetClass")
+ @CallSuper
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final ActivityTransactionItem other = (ActivityTransactionItem) o;
+ return Objects.equals(mActivityToken, other.mActivityToken);
+ }
+
+ @CallSuper
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(mActivityToken);
+ }
+
+ @CallSuper
+ @Override
+ public String toString() {
+ return "mActivityToken=" + mActivityToken;
+ }
}
diff --git a/core/java/android/app/servertransaction/ClientTransactionItem.java b/core/java/android/app/servertransaction/ClientTransactionItem.java
index fe75d89..30fc104 100644
--- a/core/java/android/app/servertransaction/ClientTransactionItem.java
+++ b/core/java/android/app/servertransaction/ClientTransactionItem.java
@@ -19,6 +19,8 @@
import static android.app.servertransaction.ActivityLifecycleItem.LifecycleState;
import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ClientTransactionHandler;
@@ -26,13 +28,15 @@
import android.os.IBinder;
import android.os.Parcelable;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* A callback message to a client that can be scheduled and executed.
* Examples of these might be activity configuration change, multi-window mode change, activity
* result delivery etc.
*
* @see ClientTransaction
- * @see com.android.server.am.ClientLifecycleManager
+ * @see com.android.server.wm.ClientLifecycleManager
* @hide
*/
public abstract class ClientTransactionItem implements BaseClientRequest, Parcelable {
@@ -57,6 +61,16 @@
return null;
}
+ /**
+ * Returns the activity token if this transaction item is activity-targeting. Otherwise,
+ * returns {@code null}.
+ */
+ @VisibleForTesting(visibility = PACKAGE)
+ @Nullable
+ public IBinder getActivityToken() {
+ return null;
+ }
+
// Parcelable
@Override
diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java
index a074286..a327a99 100644
--- a/core/java/android/app/servertransaction/DestroyActivityItem.java
+++ b/core/java/android/app/servertransaction/DestroyActivityItem.java
@@ -36,13 +36,13 @@
private int mConfigChanges;
@Override
- public void preExecute(ClientTransactionHandler client, IBinder token) {
- client.getActivitiesToBeDestroyed().put(token, this);
+ public void preExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token) {
+ client.getActivitiesToBeDestroyed().put(getActivityToken(), this);
}
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
client.handleDestroyActivity(r, mFinished, mConfigChanges,
false /* getNonConfigInstance */, "DestroyActivityItem");
@@ -54,17 +54,19 @@
return ON_DESTROY;
}
-
// ObjectPoolItem implementation
private DestroyActivityItem() {}
/** Obtain an instance initialized with provided params. */
- public static DestroyActivityItem obtain(boolean finished, int configChanges) {
+ @NonNull
+ public static DestroyActivityItem obtain(@NonNull IBinder activityToken, boolean finished,
+ int configChanges) {
DestroyActivityItem instance = ObjectPool.obtain(DestroyActivityItem.class);
if (instance == null) {
instance = new DestroyActivityItem();
}
+ instance.setActivityToken(activityToken);
instance.mFinished = finished;
instance.mConfigChanges = configChanges;
@@ -79,25 +81,25 @@
ObjectPool.recycle(this);
}
-
// Parcelable implementation
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeBoolean(mFinished);
dest.writeInt(mConfigChanges);
}
/** Read from Parcel. */
- private DestroyActivityItem(Parcel in) {
+ private DestroyActivityItem(@NonNull Parcel in) {
+ super(in);
mFinished = in.readBoolean();
mConfigChanges = in.readInt();
}
- public static final @NonNull Creator<DestroyActivityItem> CREATOR =
- new Creator<DestroyActivityItem>() {
- public DestroyActivityItem createFromParcel(Parcel in) {
+ public static final @NonNull Creator<DestroyActivityItem> CREATOR = new Creator<>() {
+ public DestroyActivityItem createFromParcel(@NonNull Parcel in) {
return new DestroyActivityItem(in);
}
@@ -111,7 +113,7 @@
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final DestroyActivityItem other = (DestroyActivityItem) o;
@@ -121,6 +123,7 @@
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + super.hashCode();
result = 31 * result + (mFinished ? 1 : 0);
result = 31 * result + mConfigChanges;
return result;
@@ -128,7 +131,8 @@
@Override
public String toString() {
- return "DestroyActivityItem{finished=" + mFinished + ",mConfigChanges="
- + mConfigChanges + "}";
+ return "DestroyActivityItem{" + super.toString()
+ + ",finished=" + mFinished
+ + ",mConfigChanges=" + mConfigChanges + "}";
}
}
diff --git a/core/java/android/app/servertransaction/EnterPipRequestedItem.java b/core/java/android/app/servertransaction/EnterPipRequestedItem.java
index 7dcae65..743653f 100644
--- a/core/java/android/app/servertransaction/EnterPipRequestedItem.java
+++ b/core/java/android/app/servertransaction/EnterPipRequestedItem.java
@@ -16,9 +16,10 @@
package android.app.servertransaction;
-import android.annotation.Nullable;
+import android.annotation.NonNull;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
+import android.os.IBinder;
import android.os.Parcel;
/**
@@ -28,8 +29,8 @@
public final class EnterPipRequestedItem extends ActivityTransactionItem {
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
client.handlePictureInPictureRequested(r);
}
@@ -38,28 +39,32 @@
private EnterPipRequestedItem() {}
/** Obtain an instance initialized with provided params. */
- public static EnterPipRequestedItem obtain() {
+ @NonNull
+ public static EnterPipRequestedItem obtain(@NonNull IBinder activityToken) {
EnterPipRequestedItem instance = ObjectPool.obtain(EnterPipRequestedItem.class);
if (instance == null) {
instance = new EnterPipRequestedItem();
}
+ instance.setActivityToken(activityToken);
return instance;
}
@Override
public void recycle() {
+ super.recycle();
ObjectPool.recycle(this);
}
// Parcelable implementation
- @Override
- public void writeToParcel(Parcel dest, int flags) { }
+ private EnterPipRequestedItem(@NonNull Parcel in) {
+ super(in);
+ }
- public static final @android.annotation.NonNull Creator<EnterPipRequestedItem> CREATOR =
- new Creator<EnterPipRequestedItem>() {
- public EnterPipRequestedItem createFromParcel(Parcel in) {
- return new EnterPipRequestedItem();
+ public static final @NonNull Creator<EnterPipRequestedItem> CREATOR =
+ new Creator<>() {
+ public EnterPipRequestedItem createFromParcel(@NonNull Parcel in) {
+ return new EnterPipRequestedItem(in);
}
public EnterPipRequestedItem[] newArray(int size) {
@@ -68,12 +73,7 @@
};
@Override
- public boolean equals(@Nullable Object o) {
- return this == o;
- }
-
- @Override
public String toString() {
- return "EnterPipRequestedItem{}";
+ return "EnterPipRequestedItem{" + super.toString() + "}";
}
}
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 5833f1b..9b37a35 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -18,6 +18,8 @@
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityClient;
@@ -39,6 +41,7 @@
import android.os.PersistableBundle;
import android.os.Trace;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
@@ -51,6 +54,7 @@
*/
public class LaunchActivityItem extends ClientTransactionItem {
+ private IBinder mActivityToken;
@UnsupportedAppUsage
private Intent mIntent;
private int mIdent;
@@ -80,7 +84,7 @@
private IActivityClientController mActivityClientController;
@Override
- public void preExecute(ClientTransactionHandler client, IBinder token) {
+ public void preExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token) {
client.countLaunchingActivities(1);
client.updateProcessState(mProcState, false);
CompatibilityInfo.applyOverrideScaleIfNeeded(mCurConfig);
@@ -92,10 +96,10 @@
}
@Override
- public void execute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull IBinder token,
+ @NonNull PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
- ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
+ ActivityClientRecord r = new ActivityClientRecord(mActivityToken, mIntent, mIdent, mInfo,
mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
@@ -105,31 +109,34 @@
}
@Override
- public void postExecute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
+ public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token,
+ @NonNull PendingTransactionActions pendingActions) {
client.countLaunchingActivities(-1);
}
-
// ObjectPoolItem implementation
private LaunchActivityItem() {}
/** Obtain an instance initialized with provided params. */
- public static LaunchActivityItem obtain(Intent intent, int ident, ActivityInfo info,
- Configuration curConfig, Configuration overrideConfig, int deviceId,
- String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
- PersistableBundle persistentState, List<ResultInfo> pendingResults,
- List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
- boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken,
- IActivityClientController activityClientController, IBinder shareableActivityToken,
- boolean launchedFromBubble, IBinder taskFragmentToken) {
+ @NonNull
+ public static LaunchActivityItem obtain(@NonNull IBinder activityToken, @NonNull Intent intent,
+ int ident, @NonNull ActivityInfo info, @NonNull Configuration curConfig,
+ @NonNull Configuration overrideConfig, int deviceId, @Nullable String referrer,
+ @Nullable IVoiceInteractor voiceInteractor, int procState, @Nullable Bundle state,
+ @Nullable PersistableBundle persistentState, @Nullable List<ResultInfo> pendingResults,
+ @Nullable List<ReferrerIntent> pendingNewIntents,
+ @Nullable ActivityOptions activityOptions,
+ boolean isForward, @Nullable ProfilerInfo profilerInfo, @NonNull IBinder assistToken,
+ @Nullable IActivityClientController activityClientController,
+ @NonNull IBinder shareableActivityToken, boolean launchedFromBubble,
+ @Nullable IBinder taskFragmentToken) {
LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
if (instance == null) {
instance = new LaunchActivityItem();
}
- setValues(instance, intent, ident, info, curConfig, overrideConfig, deviceId, referrer,
- voiceInteractor, procState, state, persistentState, pendingResults,
+ setValues(instance, activityToken, intent, ident, info, curConfig, overrideConfig, deviceId,
+ referrer, voiceInteractor, procState, state, persistentState, pendingResults,
pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken,
activityClientController, shareableActivityToken,
launchedFromBubble, taskFragmentToken);
@@ -137,19 +144,26 @@
return instance;
}
+ @VisibleForTesting(visibility = PACKAGE)
+ @NonNull
+ @Override
+ public IBinder getActivityToken() {
+ return mActivityToken;
+ }
+
@Override
public void recycle() {
- setValues(this, null, 0, null, null, null, 0, null, null, 0, null, null, null, null,
+ setValues(this, null, null, 0, null, null, null, 0, null, null, 0, null, null, null, null,
null, false, null, null, null, null, false, null);
ObjectPool.recycle(this);
}
-
// Parcelable implementation
/** Write from Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStrongBinder(mActivityToken);
dest.writeTypedObject(mIntent, flags);
dest.writeInt(mIdent);
dest.writeTypedObject(mInfo, flags);
@@ -174,8 +188,8 @@
}
/** Read from Parcel. */
- private LaunchActivityItem(Parcel in) {
- setValues(this, in.readTypedObject(Intent.CREATOR), in.readInt(),
+ private LaunchActivityItem(@NonNull Parcel in) {
+ setValues(this, in.readStrongBinder(), in.readTypedObject(Intent.CREATOR), in.readInt(),
in.readTypedObject(ActivityInfo.CREATOR), in.readTypedObject(Configuration.CREATOR),
in.readTypedObject(Configuration.CREATOR), in.readInt(), in.readString(),
IVoiceInteractor.Stub.asInterface(in.readStrongBinder()), in.readInt(),
@@ -192,9 +206,8 @@
in.readStrongBinder());
}
- public static final @NonNull Creator<LaunchActivityItem> CREATOR =
- new Creator<LaunchActivityItem>() {
- public LaunchActivityItem createFromParcel(Parcel in) {
+ public static final @NonNull Creator<LaunchActivityItem> CREATOR = new Creator<>() {
+ public LaunchActivityItem createFromParcel(@NonNull Parcel in) {
return new LaunchActivityItem(in);
}
@@ -214,7 +227,8 @@
final LaunchActivityItem other = (LaunchActivityItem) o;
final boolean intentsEqual = (mIntent == null && other.mIntent == null)
|| (mIntent != null && mIntent.filterEquals(other.mIntent));
- return intentsEqual && mIdent == other.mIdent
+ return intentsEqual
+ && Objects.equals(mActivityToken, other.mActivityToken) && mIdent == other.mIdent
&& activityInfoEqual(other.mInfo) && Objects.equals(mCurConfig, other.mCurConfig)
&& Objects.equals(mOverrideConfig, other.mOverrideConfig)
&& mDeviceId == other.mDeviceId
@@ -234,6 +248,7 @@
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + Objects.hashCode(mActivityToken);
result = 31 * result + mIntent.filterHashCode();
result = 31 * result + mIdent;
result = 31 * result + Objects.hashCode(mCurConfig);
@@ -254,7 +269,7 @@
return result;
}
- private boolean activityInfoEqual(ActivityInfo other) {
+ private boolean activityInfoEqual(@Nullable ActivityInfo other) {
if (mInfo == null) {
return other == null;
}
@@ -270,36 +285,51 @@
* unparceling if a customized class loader is not set to the bundle. So the hash code is
* simply determined by the bundle is empty or not.
*/
- private static int getRoughBundleHashCode(BaseBundle bundle) {
+ private static int getRoughBundleHashCode(@Nullable BaseBundle bundle) {
return (bundle == null || bundle.isDefinitelyEmpty()) ? 0 : 1;
}
/** Compares the bundles without unparceling them (avoid BadParcelableException). */
- private static boolean areBundlesEqualRoughly(BaseBundle a, BaseBundle b) {
+ private static boolean areBundlesEqualRoughly(@Nullable BaseBundle a, @Nullable BaseBundle b) {
return getRoughBundleHashCode(a) == getRoughBundleHashCode(b);
}
@Override
public String toString() {
- return "LaunchActivityItem{intent=" + mIntent + ",ident=" + mIdent + ",info=" + mInfo
- + ",curConfig=" + mCurConfig + ",overrideConfig=" + mOverrideConfig
- + ",deviceId=" + mDeviceId + ",referrer=" + mReferrer + ",procState=" + mProcState
- + ",state=" + mState + ",persistentState=" + mPersistentState
- + ",pendingResults=" + mPendingResults + ",pendingNewIntents=" + mPendingNewIntents
- + ",options=" + mActivityOptions + ",profilerInfo=" + mProfilerInfo
- + ",assistToken=" + mAssistToken + ",shareableActivityToken="
- + mShareableActivityToken + "}";
+ return "LaunchActivityItem{activityToken=" + mActivityToken
+ + ",intent=" + mIntent
+ + ",ident=" + mIdent
+ + ",info=" + mInfo
+ + ",curConfig=" + mCurConfig
+ + ",overrideConfig=" + mOverrideConfig
+ + ",deviceId=" + mDeviceId
+ + ",referrer=" + mReferrer
+ + ",procState=" + mProcState
+ + ",state=" + mState
+ + ",persistentState=" + mPersistentState
+ + ",pendingResults=" + mPendingResults
+ + ",pendingNewIntents=" + mPendingNewIntents
+ + ",options=" + mActivityOptions
+ + ",profilerInfo=" + mProfilerInfo
+ + ",assistToken=" + mAssistToken
+ + ",shareableActivityToken=" + mShareableActivityToken + "}";
}
// Using the same method to set and clear values to make sure we don't forget anything
- private static void setValues(LaunchActivityItem instance, Intent intent, int ident,
- ActivityInfo info, Configuration curConfig, Configuration overrideConfig, int deviceId,
- String referrer, IVoiceInteractor voiceInteractor,
- int procState, Bundle state, PersistableBundle persistentState,
- List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
- ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo,
- IBinder assistToken, IActivityClientController activityClientController,
- IBinder shareableActivityToken, boolean launchedFromBubble, IBinder taskFragmentToken) {
+ private static void setValues(@Nullable LaunchActivityItem instance,
+ @Nullable IBinder activityToken, @Nullable Intent intent, int ident,
+ @Nullable ActivityInfo info, @Nullable Configuration curConfig,
+ @Nullable Configuration overrideConfig, int deviceId,
+ @Nullable String referrer, @Nullable IVoiceInteractor voiceInteractor,
+ int procState, @Nullable Bundle state, @Nullable PersistableBundle persistentState,
+ @Nullable List<ResultInfo> pendingResults,
+ @Nullable List<ReferrerIntent> pendingNewIntents,
+ @Nullable ActivityOptions activityOptions, boolean isForward,
+ @Nullable ProfilerInfo profilerInfo, @Nullable IBinder assistToken,
+ @Nullable IActivityClientController activityClientController,
+ @Nullable IBinder shareableActivityToken, boolean launchedFromBubble,
+ @Nullable IBinder taskFragmentToken) {
+ instance.mActivityToken = activityToken;
instance.mIntent = intent;
instance.mIdent = ident;
instance.mInfo = info;
diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java
index f13bd74..fb57bed 100644
--- a/core/java/android/app/servertransaction/MoveToDisplayItem.java
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -40,37 +40,34 @@
private Configuration mConfiguration;
@Override
- public void preExecute(ClientTransactionHandler client, IBinder token) {
+ public void preExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token) {
CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration);
// Notify the client of an upcoming change in the token configuration. This ensures that
// batches of config change items only process the newest configuration.
- client.updatePendingActivityConfiguration(token, mConfiguration);
+ client.updatePendingActivityConfiguration(getActivityToken(), mConfiguration);
}
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay");
client.handleActivityConfigurationChanged(r, mConfiguration, mTargetDisplayId);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
-
// ObjectPoolItem implementation
private MoveToDisplayItem() {}
/** Obtain an instance initialized with provided params. */
- public static MoveToDisplayItem obtain(int targetDisplayId,
+ @NonNull
+ public static MoveToDisplayItem obtain(@NonNull IBinder activityToken, int targetDisplayId,
@NonNull Configuration configuration) {
- if (configuration == null) {
- throw new IllegalArgumentException("Configuration must not be null");
- }
-
MoveToDisplayItem instance = ObjectPool.obtain(MoveToDisplayItem.class);
if (instance == null) {
instance = new MoveToDisplayItem();
}
+ instance.setActivityToken(activityToken);
instance.mTargetDisplayId = targetDisplayId;
instance.mConfiguration = configuration;
@@ -79,30 +76,31 @@
@Override
public void recycle() {
+ super.recycle();
mTargetDisplayId = 0;
mConfiguration = Configuration.EMPTY;
ObjectPool.recycle(this);
}
-
// Parcelable implementation
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeInt(mTargetDisplayId);
dest.writeTypedObject(mConfiguration, flags);
}
/** Read from Parcel. */
- private MoveToDisplayItem(Parcel in) {
+ private MoveToDisplayItem(@NonNull Parcel in) {
+ super(in);
mTargetDisplayId = in.readInt();
mConfiguration = in.readTypedObject(Configuration.CREATOR);
}
- public static final @NonNull Creator<MoveToDisplayItem> CREATOR =
- new Creator<MoveToDisplayItem>() {
- public MoveToDisplayItem createFromParcel(Parcel in) {
+ public static final @NonNull Creator<MoveToDisplayItem> CREATOR = new Creator<>() {
+ public MoveToDisplayItem createFromParcel(@NonNull Parcel in) {
return new MoveToDisplayItem(in);
}
@@ -116,7 +114,7 @@
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final MoveToDisplayItem other = (MoveToDisplayItem) o;
@@ -127,6 +125,7 @@
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + super.hashCode();
result = 31 * result + mTargetDisplayId;
result = 31 * result + mConfiguration.hashCode();
return result;
@@ -134,7 +133,8 @@
@Override
public String toString() {
- return "MoveToDisplayItem{targetDisplayId=" + mTargetDisplayId
+ return "MoveToDisplayItem{" + super.toString()
+ + ",targetDisplayId=" + mTargetDisplayId
+ ",configuration=" + mConfiguration + "}";
}
}
diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java
index 723fa01..8e995aa 100644
--- a/core/java/android/app/servertransaction/NewIntentItem.java
+++ b/core/java/android/app/servertransaction/NewIntentItem.java
@@ -25,6 +25,7 @@
import android.app.ClientTransactionHandler;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Trace;
@@ -50,24 +51,26 @@
}
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent");
client.handleNewIntent(r, mIntents);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
-
// ObjectPoolItem implementation
private NewIntentItem() {}
/** Obtain an instance initialized with provided params. */
- public static NewIntentItem obtain(List<ReferrerIntent> intents, boolean resume) {
+ @NonNull
+ public static NewIntentItem obtain(@NonNull IBinder activityToken,
+ @NonNull List<ReferrerIntent> intents, boolean resume) {
NewIntentItem instance = ObjectPool.obtain(NewIntentItem.class);
if (instance == null) {
instance = new NewIntentItem();
}
+ instance.setActivityToken(activityToken);
instance.mIntents = intents;
instance.mResume = resume;
@@ -76,44 +79,46 @@
@Override
public void recycle() {
+ super.recycle();
mIntents = null;
mResume = false;
ObjectPool.recycle(this);
}
-
// Parcelable implementation
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeBoolean(mResume);
dest.writeTypedList(mIntents, flags);
}
/** Read from Parcel. */
- private NewIntentItem(Parcel in) {
+ private NewIntentItem(@NonNull Parcel in) {
+ super(in);
mResume = in.readBoolean();
mIntents = in.createTypedArrayList(ReferrerIntent.CREATOR);
}
public static final @NonNull Parcelable.Creator<NewIntentItem> CREATOR =
- new Parcelable.Creator<NewIntentItem>() {
- public NewIntentItem createFromParcel(Parcel in) {
- return new NewIntentItem(in);
- }
+ new Parcelable.Creator<>() {
+ public NewIntentItem createFromParcel(@NonNull Parcel in) {
+ return new NewIntentItem(in);
+ }
- public NewIntentItem[] newArray(int size) {
- return new NewIntentItem[size];
- }
- };
+ public NewIntentItem[] newArray(int size) {
+ return new NewIntentItem[size];
+ }
+ };
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final NewIntentItem other = (NewIntentItem) o;
@@ -123,6 +128,7 @@
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + super.hashCode();
result = 31 * result + (mResume ? 1 : 0);
result = 31 * result + mIntents.hashCode();
return result;
@@ -130,6 +136,8 @@
@Override
public String toString() {
- return "NewIntentItem{intents=" + mIntents + ",resume=" + mResume + "}";
+ return "NewIntentItem{" + super.toString()
+ + ",intents=" + mIntents
+ + ",resume=" + mResume + "}";
}
}
diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java
index 965e761..a8e6772 100644
--- a/core/java/android/app/servertransaction/PauseActivityItem.java
+++ b/core/java/android/app/servertransaction/PauseActivityItem.java
@@ -42,8 +42,8 @@
private boolean mAutoEnteringPip;
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
client.handlePauseActivity(r, mFinished, mUserLeaving, mConfigChanges, mAutoEnteringPip,
pendingActions, "PAUSE_ACTIVITY_ITEM");
@@ -56,27 +56,28 @@
}
@Override
- public void postExecute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
+ public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token,
+ @NonNull PendingTransactionActions pendingActions) {
if (mDontReport) {
return;
}
// TODO(lifecycler): Use interface callback instead of actual implementation.
- ActivityClient.getInstance().activityPaused(token);
+ ActivityClient.getInstance().activityPaused(getActivityToken());
}
-
// ObjectPoolItem implementation
private PauseActivityItem() {}
/** Obtain an instance initialized with provided params. */
- public static PauseActivityItem obtain(boolean finished, boolean userLeaving, int configChanges,
- boolean dontReport, boolean autoEnteringPip) {
+ @NonNull
+ public static PauseActivityItem obtain(@NonNull IBinder activityToken, boolean finished,
+ boolean userLeaving, int configChanges, boolean dontReport, boolean autoEnteringPip) {
PauseActivityItem instance = ObjectPool.obtain(PauseActivityItem.class);
if (instance == null) {
instance = new PauseActivityItem();
}
+ instance.setActivityToken(activityToken);
instance.mFinished = finished;
instance.mUserLeaving = userLeaving;
instance.mConfigChanges = configChanges;
@@ -87,18 +88,10 @@
}
/** Obtain an instance initialized with default params. */
- public static PauseActivityItem obtain() {
- PauseActivityItem instance = ObjectPool.obtain(PauseActivityItem.class);
- if (instance == null) {
- instance = new PauseActivityItem();
- }
- instance.mFinished = false;
- instance.mUserLeaving = false;
- instance.mConfigChanges = 0;
- instance.mDontReport = true;
- instance.mAutoEnteringPip = false;
-
- return instance;
+ @NonNull
+ public static PauseActivityItem obtain(@NonNull IBinder activityToken) {
+ return obtain(activityToken, false /* finished */, false /* userLeaving */,
+ 0 /* configChanges */, true /* dontReport */, false /* autoEnteringPip*/);
}
@Override
@@ -116,7 +109,8 @@
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeBoolean(mFinished);
dest.writeBoolean(mUserLeaving);
dest.writeInt(mConfigChanges);
@@ -125,7 +119,8 @@
}
/** Read from Parcel. */
- private PauseActivityItem(Parcel in) {
+ private PauseActivityItem(@NonNull Parcel in) {
+ super(in);
mFinished = in.readBoolean();
mUserLeaving = in.readBoolean();
mConfigChanges = in.readInt();
@@ -133,9 +128,8 @@
mAutoEnteringPip = in.readBoolean();
}
- public static final @NonNull Creator<PauseActivityItem> CREATOR =
- new Creator<PauseActivityItem>() {
- public PauseActivityItem createFromParcel(Parcel in) {
+ public static final @NonNull Creator<PauseActivityItem> CREATOR = new Creator<>() {
+ public PauseActivityItem createFromParcel(@NonNull Parcel in) {
return new PauseActivityItem(in);
}
@@ -149,7 +143,7 @@
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final PauseActivityItem other = (PauseActivityItem) o;
@@ -161,6 +155,7 @@
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + super.hashCode();
result = 31 * result + (mFinished ? 1 : 0);
result = 31 * result + (mUserLeaving ? 1 : 0);
result = 31 * result + mConfigChanges;
@@ -171,8 +166,11 @@
@Override
public String toString() {
- return "PauseActivityItem{finished=" + mFinished + ",userLeaving=" + mUserLeaving
- + ",configChanges=" + mConfigChanges + ",dontReport=" + mDontReport
+ return "PauseActivityItem{" + super.toString()
+ + ",finished=" + mFinished
+ + ",userLeaving=" + mUserLeaving
+ + ",configChanges=" + mConfigChanges
+ + ",dontReport=" + mDontReport
+ ",autoEnteringPip=" + mAutoEnteringPip + "}";
}
}
diff --git a/core/java/android/app/servertransaction/PipStateTransactionItem.java b/core/java/android/app/servertransaction/PipStateTransactionItem.java
index 167f5a4..30289ef 100644
--- a/core/java/android/app/servertransaction/PipStateTransactionItem.java
+++ b/core/java/android/app/servertransaction/PipStateTransactionItem.java
@@ -16,12 +16,16 @@
package android.app.servertransaction;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.app.PictureInPictureUiState;
+import android.os.IBinder;
import android.os.Parcel;
+import java.util.Objects;
+
/**
* Request an activity to enter picture-in-picture mode.
* @hide
@@ -31,8 +35,8 @@
private PictureInPictureUiState mPipState;
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
client.handlePictureInPictureStateChanged(r, mPipState);
}
@@ -41,11 +45,14 @@
private PipStateTransactionItem() {}
/** Obtain an instance initialized with provided params. */
- public static PipStateTransactionItem obtain(PictureInPictureUiState pipState) {
+ @NonNull
+ public static PipStateTransactionItem obtain(@NonNull IBinder activityToken,
+ @NonNull PictureInPictureUiState pipState) {
PipStateTransactionItem instance = ObjectPool.obtain(PipStateTransactionItem.class);
if (instance == null) {
instance = new PipStateTransactionItem();
}
+ instance.setActivityToken(activityToken);
instance.mPipState = pipState;
return instance;
@@ -53,6 +60,7 @@
@Override
public void recycle() {
+ super.recycle();
mPipState = null;
ObjectPool.recycle(this);
}
@@ -61,33 +69,49 @@
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
mPipState.writeToParcel(dest, flags);
}
/** Read from Parcel. */
- private PipStateTransactionItem(Parcel in) {
+ private PipStateTransactionItem(@NonNull Parcel in) {
+ super(in);
mPipState = PictureInPictureUiState.CREATOR.createFromParcel(in);
}
- public static final @android.annotation.NonNull Creator<PipStateTransactionItem> CREATOR =
- new Creator<PipStateTransactionItem>() {
- public PipStateTransactionItem createFromParcel(Parcel in) {
- return new PipStateTransactionItem(in);
- }
+ public static final @NonNull Creator<PipStateTransactionItem> CREATOR = new Creator<>() {
+ public PipStateTransactionItem createFromParcel(@NonNull Parcel in) {
+ return new PipStateTransactionItem(in);
+ }
- public PipStateTransactionItem[] newArray(int size) {
- return new PipStateTransactionItem[size];
- }
- };
+ public PipStateTransactionItem[] newArray(int size) {
+ return new PipStateTransactionItem[size];
+ }
+ };
@Override
public boolean equals(@Nullable Object o) {
- return this == o;
+ if (this == o) {
+ return true;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ final PipStateTransactionItem other = (PipStateTransactionItem) o;
+ return Objects.equals(mPipState, other.mPipState);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + super.hashCode();
+ result = 31 * result + Objects.hashCode(mPipState);
+ return result;
}
@Override
public String toString() {
- return "PipStateTransactionItem{}";
+ return "PipStateTransactionItem{" + super.toString() + "}";
}
}
diff --git a/core/java/android/app/servertransaction/RefreshCallbackItem.java b/core/java/android/app/servertransaction/RefreshCallbackItem.java
index 74abab2..00128f0 100644
--- a/core/java/android/app/servertransaction/RefreshCallbackItem.java
+++ b/core/java/android/app/servertransaction/RefreshCallbackItem.java
@@ -48,12 +48,12 @@
@Override
public void execute(@NonNull ClientTransactionHandler client,
- @NonNull ActivityClientRecord r, PendingTransactionActions pendingActions) {}
+ @NonNull ActivityClientRecord r, @NonNull PendingTransactionActions pendingActions) {}
@Override
- public void postExecute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
- final ActivityClientRecord r = getActivityClientRecord(client, token);
+ public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token,
+ @NonNull PendingTransactionActions pendingActions) {
+ final ActivityClientRecord r = getActivityClientRecord(client);
client.reportRefresh(r);
}
@@ -71,6 +71,7 @@
@Override
public void recycle() {
+ super.recycle();
ObjectPool.recycle(this);
}
@@ -79,7 +80,9 @@
* @param postExecutionState indicating whether refresh should happen using the
* "stopped -> resumed" cycle or "paused -> resumed" cycle.
*/
- public static RefreshCallbackItem obtain(@LifecycleState int postExecutionState) {
+ @NonNull
+ public static RefreshCallbackItem obtain(@NonNull IBinder activityToken,
+ @LifecycleState int postExecutionState) {
if (postExecutionState != ON_STOP && postExecutionState != ON_PAUSE) {
throw new IllegalArgumentException(
"Only ON_STOP or ON_PAUSE are allowed as a post execution state for "
@@ -90,6 +93,7 @@
if (instance == null) {
instance = new RefreshCallbackItem();
}
+ instance.setActivityToken(activityToken);
instance.mPostExecutionState = postExecutionState;
return instance;
}
@@ -99,7 +103,8 @@
// Parcelable implementation
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeInt(mPostExecutionState);
}
@@ -108,7 +113,7 @@
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final RefreshCallbackItem other = (RefreshCallbackItem) o;
@@ -118,23 +123,25 @@
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + super.hashCode();
result = 31 * result + mPostExecutionState;
return result;
}
@Override
public String toString() {
- return "RefreshCallbackItem{mPostExecutionState=" + mPostExecutionState + "}";
+ return "RefreshCallbackItem{" + super.toString()
+ + ",mPostExecutionState=" + mPostExecutionState + "}";
}
- private RefreshCallbackItem(Parcel in) {
+ private RefreshCallbackItem(@NonNull Parcel in) {
+ super(in);
mPostExecutionState = in.readInt();
}
- public static final @NonNull Creator<RefreshCallbackItem> CREATOR =
- new Creator<RefreshCallbackItem>() {
+ public static final @NonNull Creator<RefreshCallbackItem> CREATOR = new Creator<>() {
- public RefreshCallbackItem createFromParcel(Parcel in) {
+ public RefreshCallbackItem createFromParcel(@NonNull Parcel in) {
return new RefreshCallbackItem(in);
}
diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java
index 222f8ca..b11e73c 100644
--- a/core/java/android/app/servertransaction/ResumeActivityItem.java
+++ b/core/java/android/app/servertransaction/ResumeActivityItem.java
@@ -44,15 +44,15 @@
private boolean mShouldSendCompatFakeFocus;
@Override
- public void preExecute(ClientTransactionHandler client, IBinder token) {
+ public void preExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token) {
if (mUpdateProcState) {
client.updateProcessState(mProcState, false);
}
}
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward,
mShouldSendCompatFakeFocus, "RESUME_ACTIVITY");
@@ -60,10 +60,11 @@
}
@Override
- public void postExecute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
+ public void postExecute(@NonNull ClientTransactionHandler client, IBinder token,
+ @NonNull PendingTransactionActions pendingActions) {
// TODO(lifecycler): Use interface callback instead of actual implementation.
- ActivityClient.getInstance().activityResumed(token, client.isHandleSplashScreenExit(token));
+ ActivityClient.getInstance().activityResumed(getActivityToken(),
+ client.isHandleSplashScreenExit(getActivityToken()));
}
@Override
@@ -71,18 +72,19 @@
return ON_RESUME;
}
-
// ObjectPoolItem implementation
private ResumeActivityItem() {}
/** Obtain an instance initialized with provided params. */
- public static ResumeActivityItem obtain(int procState, boolean isForward,
- boolean shouldSendCompatFakeFocus) {
+ @NonNull
+ public static ResumeActivityItem obtain(@NonNull IBinder activityToken, int procState,
+ boolean isForward, boolean shouldSendCompatFakeFocus) {
ResumeActivityItem instance = ObjectPool.obtain(ResumeActivityItem.class);
if (instance == null) {
instance = new ResumeActivityItem();
}
+ instance.setActivityToken(activityToken);
instance.mProcState = procState;
instance.mUpdateProcState = true;
instance.mIsForward = isForward;
@@ -92,11 +94,14 @@
}
/** Obtain an instance initialized with provided params. */
- public static ResumeActivityItem obtain(boolean isForward, boolean shouldSendCompatFakeFocus) {
+ @NonNull
+ public static ResumeActivityItem obtain(@NonNull IBinder activityToken, boolean isForward,
+ boolean shouldSendCompatFakeFocus) {
ResumeActivityItem instance = ObjectPool.obtain(ResumeActivityItem.class);
if (instance == null) {
instance = new ResumeActivityItem();
}
+ instance.setActivityToken(activityToken);
instance.mProcState = ActivityManager.PROCESS_STATE_UNKNOWN;
instance.mUpdateProcState = false;
instance.mIsForward = isForward;
@@ -115,12 +120,12 @@
ObjectPool.recycle(this);
}
-
// Parcelable implementation
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeInt(mProcState);
dest.writeBoolean(mUpdateProcState);
dest.writeBoolean(mIsForward);
@@ -128,15 +133,15 @@
}
/** Read from Parcel. */
- private ResumeActivityItem(Parcel in) {
+ private ResumeActivityItem(@NonNull Parcel in) {
+ super(in);
mProcState = in.readInt();
mUpdateProcState = in.readBoolean();
mIsForward = in.readBoolean();
mShouldSendCompatFakeFocus = in.readBoolean();
}
- public static final @NonNull Creator<ResumeActivityItem> CREATOR =
- new Creator<ResumeActivityItem>() {
+ public static final @NonNull Creator<ResumeActivityItem> CREATOR = new Creator<>() {
public ResumeActivityItem createFromParcel(Parcel in) {
return new ResumeActivityItem(in);
}
@@ -151,7 +156,7 @@
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final ResumeActivityItem other = (ResumeActivityItem) o;
@@ -163,6 +168,7 @@
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + super.hashCode();
result = 31 * result + mProcState;
result = 31 * result + (mUpdateProcState ? 1 : 0);
result = 31 * result + (mIsForward ? 1 : 0);
@@ -172,8 +178,10 @@
@Override
public String toString() {
- return "ResumeActivityItem{procState=" + mProcState
- + ",updateProcState=" + mUpdateProcState + ",isForward=" + mIsForward
+ return "ResumeActivityItem{" + super.toString()
+ + ",procState=" + mProcState
+ + ",updateProcState=" + mUpdateProcState
+ + ",isForward=" + mIsForward
+ ",shouldSendCompatFakeFocus=" + mShouldSendCompatFakeFocus + "}";
}
}
diff --git a/core/java/android/app/servertransaction/StartActivityItem.java b/core/java/android/app/servertransaction/StartActivityItem.java
index 15f65f6..8b98b21 100644
--- a/core/java/android/app/servertransaction/StartActivityItem.java
+++ b/core/java/android/app/servertransaction/StartActivityItem.java
@@ -23,6 +23,7 @@
import android.app.ActivityOptions;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Trace;
@@ -37,8 +38,8 @@
private ActivityOptions mActivityOptions;
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "startActivityItem");
client.handleStartActivity(r, pendingActions, mActivityOptions);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
@@ -49,17 +50,19 @@
return ON_START;
}
-
// ObjectPoolItem implementation
private StartActivityItem() {}
/** Obtain an instance initialized with provided params. */
- public static StartActivityItem obtain(ActivityOptions activityOptions) {
+ @NonNull
+ public static StartActivityItem obtain(@NonNull IBinder activityToken,
+ @Nullable ActivityOptions activityOptions) {
StartActivityItem instance = ObjectPool.obtain(StartActivityItem.class);
if (instance == null) {
instance = new StartActivityItem();
}
+ instance.setActivityToken(activityToken);
instance.mActivityOptions = activityOptions;
return instance;
@@ -72,37 +75,37 @@
ObjectPool.recycle(this);
}
-
// Parcelable implementation
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeBundle(mActivityOptions != null ? mActivityOptions.toBundle() : null);
}
/** Read from Parcel. */
- private StartActivityItem(Parcel in) {
+ private StartActivityItem(@NonNull Parcel in) {
+ super(in);
mActivityOptions = ActivityOptions.fromBundle(in.readBundle());
}
- public static final @NonNull Creator<StartActivityItem> CREATOR =
- new Creator<StartActivityItem>() {
- public StartActivityItem createFromParcel(Parcel in) {
- return new StartActivityItem(in);
- }
+ public static final @NonNull Creator<StartActivityItem> CREATOR = new Creator<>() {
+ public StartActivityItem createFromParcel(@NonNull Parcel in) {
+ return new StartActivityItem(in);
+ }
- public StartActivityItem[] newArray(int size) {
- return new StartActivityItem[size];
- }
- };
+ public StartActivityItem[] newArray(int size) {
+ return new StartActivityItem[size];
+ }
+ };
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final StartActivityItem other = (StartActivityItem) o;
@@ -112,13 +115,15 @@
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + super.hashCode();
result = 31 * result + (mActivityOptions != null ? 1 : 0);
return result;
}
@Override
public String toString() {
- return "StartActivityItem{options=" + mActivityOptions + "}";
+ return "StartActivityItem{" + super.toString()
+ + ",options=" + mActivityOptions + "}";
}
}
diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java
index 7e9116d..f432567 100644
--- a/core/java/android/app/servertransaction/StopActivityItem.java
+++ b/core/java/android/app/servertransaction/StopActivityItem.java
@@ -37,8 +37,8 @@
private int mConfigChanges;
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
client.handleStopActivity(r, mConfigChanges, pendingActions,
true /* finalStateRequest */, "STOP_ACTIVITY_ITEM");
@@ -46,8 +46,8 @@
}
@Override
- public void postExecute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
+ public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token,
+ @NonNull PendingTransactionActions pendingActions) {
client.reportStop(pendingActions);
}
@@ -56,20 +56,22 @@
return ON_STOP;
}
-
// ObjectPoolItem implementation
private StopActivityItem() {}
/**
* Obtain an instance initialized with provided params.
+ * @param activityToken the activity that stops.
* @param configChanges Configuration pieces that changed.
*/
- public static StopActivityItem obtain(int configChanges) {
+ @NonNull
+ public static StopActivityItem obtain(@NonNull IBinder activityToken, int configChanges) {
StopActivityItem instance = ObjectPool.obtain(StopActivityItem.class);
if (instance == null) {
instance = new StopActivityItem();
}
+ instance.setActivityToken(activityToken);
instance.mConfigChanges = configChanges;
return instance;
@@ -82,23 +84,23 @@
ObjectPool.recycle(this);
}
-
// Parcelable implementation
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeInt(mConfigChanges);
}
/** Read from Parcel. */
- private StopActivityItem(Parcel in) {
+ private StopActivityItem(@NonNull Parcel in) {
+ super(in);
mConfigChanges = in.readInt();
}
- public static final @NonNull Creator<StopActivityItem> CREATOR =
- new Creator<StopActivityItem>() {
- public StopActivityItem createFromParcel(Parcel in) {
+ public static final @NonNull Creator<StopActivityItem> CREATOR = new Creator<>() {
+ public StopActivityItem createFromParcel(@NonNull Parcel in) {
return new StopActivityItem(in);
}
@@ -112,7 +114,7 @@
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final StopActivityItem other = (StopActivityItem) o;
@@ -122,12 +124,14 @@
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + super.hashCode();
result = 31 * result + mConfigChanges;
return result;
}
@Override
public String toString() {
- return "StopActivityItem{configChanges=" + mConfigChanges + "}";
+ return "StopActivityItem{" + super.toString()
+ + ",configChanges=" + mConfigChanges + "}";
}
}
diff --git a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
index 5cd3d68f..693599f 100644
--- a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
+++ b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
@@ -35,16 +35,16 @@
private boolean mOnTop;
@Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
+ @NonNull PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "topResumedActivityChangeItem");
client.handleTopResumedActivityChanged(r, mOnTop, "topResumedActivityChangeItem");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@Override
- public void postExecute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
+ public void postExecute(@NonNull ClientTransactionHandler client, @NonNull IBinder token,
+ @NonNull PendingTransactionActions pendingActions) {
if (mOnTop) {
return;
}
@@ -58,18 +58,20 @@
ActivityClient.getInstance().activityTopResumedStateLost();
}
-
// ObjectPoolItem implementation
private TopResumedActivityChangeItem() {}
/** Obtain an instance initialized with provided params. */
- public static TopResumedActivityChangeItem obtain(boolean onTop) {
+ @NonNull
+ public static TopResumedActivityChangeItem obtain(@NonNull IBinder activityToken,
+ boolean onTop) {
TopResumedActivityChangeItem instance =
ObjectPool.obtain(TopResumedActivityChangeItem.class);
if (instance == null) {
instance = new TopResumedActivityChangeItem();
}
+ instance.setActivityToken(activityToken);
instance.mOnTop = onTop;
return instance;
@@ -77,27 +79,28 @@
@Override
public void recycle() {
+ super.recycle();
mOnTop = false;
ObjectPool.recycle(this);
}
-
// Parcelable implementation
/** Write to Parcel. */
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeBoolean(mOnTop);
}
/** Read from Parcel. */
- private TopResumedActivityChangeItem(Parcel in) {
+ private TopResumedActivityChangeItem(@NonNull Parcel in) {
+ super(in);
mOnTop = in.readBoolean();
}
- public static final @NonNull Creator<TopResumedActivityChangeItem> CREATOR =
- new Creator<TopResumedActivityChangeItem>() {
- public TopResumedActivityChangeItem createFromParcel(Parcel in) {
+ public static final @NonNull Creator<TopResumedActivityChangeItem> CREATOR = new Creator<>() {
+ public TopResumedActivityChangeItem createFromParcel(@NonNull Parcel in) {
return new TopResumedActivityChangeItem(in);
}
@@ -111,7 +114,7 @@
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (!super.equals(o)) {
return false;
}
final TopResumedActivityChangeItem other = (TopResumedActivityChangeItem) o;
@@ -121,12 +124,14 @@
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + super.hashCode();
result = 31 * result + (mOnTop ? 1 : 0);
return result;
}
@Override
public String toString() {
- return "TopResumedActivityChangeItem{onTop=" + mOnTop + "}";
+ return "TopResumedActivityChangeItem{" + super.toString()
+ + ",onTop=" + mOnTop + "}";
}
}
diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
index baf2a47..0f9c517 100644
--- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java
+++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
@@ -196,13 +196,13 @@
// Fall through to return the PAUSE item to ensure the activity is properly
// resumed while relaunching.
case ON_PAUSE:
- lifecycleItem = PauseActivityItem.obtain();
+ lifecycleItem = PauseActivityItem.obtain(r.token);
break;
case ON_STOP:
- lifecycleItem = StopActivityItem.obtain(0 /* configChanges */);
+ lifecycleItem = StopActivityItem.obtain(r.token, 0 /* configChanges */);
break;
default:
- lifecycleItem = ResumeActivityItem.obtain(false /* isForward */,
+ lifecycleItem = ResumeActivityItem.obtain(r.token, false /* isForward */,
false /* shouldSendCompatFakeFocus */);
break;
}
diff --git a/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java b/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java
index 767fd28..11947e9 100644
--- a/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java
+++ b/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java
@@ -20,10 +20,13 @@
import android.annotation.Nullable;
import android.app.ActivityThread;
import android.app.ClientTransactionHandler;
+import android.os.IBinder;
import android.os.Parcel;
import android.view.SurfaceControl;
import android.window.SplashScreenView.SplashScreenViewParcelable;
+import java.util.Objects;
+
/**
* Transfer a splash screen view to an Activity.
* @hide
@@ -36,36 +39,44 @@
@Override
public void execute(@NonNull ClientTransactionHandler client,
@NonNull ActivityThread.ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ @NonNull PendingTransactionActions pendingActions) {
client.handleAttachSplashScreenView(r, mSplashScreenViewParcelable, mStartingWindowLeash);
}
@Override
public void recycle() {
+ super.recycle();
+ mSplashScreenViewParcelable = null;
+ mStartingWindowLeash = null;
ObjectPool.recycle(this);
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
dest.writeTypedObject(mSplashScreenViewParcelable, flags);
dest.writeTypedObject(mStartingWindowLeash, flags);
}
private TransferSplashScreenViewStateItem() {}
- private TransferSplashScreenViewStateItem(Parcel in) {
+
+ private TransferSplashScreenViewStateItem(@NonNull Parcel in) {
+ super(in);
mSplashScreenViewParcelable = in.readTypedObject(SplashScreenViewParcelable.CREATOR);
mStartingWindowLeash = in.readTypedObject(SurfaceControl.CREATOR);
}
/** Obtain an instance initialized with provided params. */
+ @NonNull
public static TransferSplashScreenViewStateItem obtain(
- @Nullable SplashScreenViewParcelable parcelable,
+ @NonNull IBinder activityToken, @Nullable SplashScreenViewParcelable parcelable,
@Nullable SurfaceControl startingWindowLeash) {
TransferSplashScreenViewStateItem instance =
ObjectPool.obtain(TransferSplashScreenViewStateItem.class);
if (instance == null) {
instance = new TransferSplashScreenViewStateItem();
}
+ instance.setActivityToken(activityToken);
instance.mSplashScreenViewParcelable = parcelable;
instance.mStartingWindowLeash = startingWindowLeash;
@@ -73,8 +84,8 @@
}
public static final @NonNull Creator<TransferSplashScreenViewStateItem> CREATOR =
- new Creator<TransferSplashScreenViewStateItem>() {
- public TransferSplashScreenViewStateItem createFromParcel(Parcel in) {
+ new Creator<>() {
+ public TransferSplashScreenViewStateItem createFromParcel(@NonNull Parcel in) {
return new TransferSplashScreenViewStateItem(in);
}
@@ -82,4 +93,33 @@
return new TransferSplashScreenViewStateItem[size];
}
};
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ final TransferSplashScreenViewStateItem other = (TransferSplashScreenViewStateItem) o;
+ return Objects.equals(mSplashScreenViewParcelable, other.mSplashScreenViewParcelable)
+ && Objects.equals(mStartingWindowLeash, other.mStartingWindowLeash);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + super.hashCode();
+ result = 31 * result + Objects.hashCode(mSplashScreenViewParcelable);
+ result = 31 * result + Objects.hashCode(mStartingWindowLeash);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "TransferSplashScreenViewStateItem{" + super.toString()
+ + ",splashScreenViewParcelable=" + mSplashScreenViewParcelable
+ + ",startingWindowLeash=" + mStartingWindowLeash + "}";
+ }
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 3aa2877..2fb428b 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -39,6 +39,7 @@
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.companion.datatransfer.PermissionSyncRequest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -180,7 +181,7 @@
public @interface DataSyncTypes {}
/**
- * Used by {@link #enableSystemDataSync(int, int)}}.
+ * Used by {@link #enableSystemDataSyncForTypes(int, int)}}.
* Sync call metadata like muting, ending and silencing a call.
*
*/
@@ -552,6 +553,39 @@
}
/**
+ * @hide
+ */
+ public void enablePermissionsSync(int associationId) {
+ try {
+ mService.enablePermissionsSync(associationId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void disablePermissionsSync(int associationId) {
+ try {
+ mService.disablePermissionsSync(associationId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public PermissionSyncRequest getPermissionSyncRequest(int associationId) {
+ try {
+ return mService.getPermissionSyncRequest(associationId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* <p>Calling this API requires a uses-feature
* {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p>
*
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index a3b202a..c5a1988 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -24,6 +24,7 @@
import android.companion.ISystemDataTransferCallback;
import android.companion.AssociationInfo;
import android.companion.AssociationRequest;
+import android.companion.datatransfer.PermissionSyncRequest;
import android.content.ComponentName;
/**
@@ -113,6 +114,12 @@
void disableSystemDataSync(int associationId, int flags);
+ void enablePermissionsSync(int associationId);
+
+ void disablePermissionsSync(int associationId);
+
+ PermissionSyncRequest getPermissionSyncRequest(int associationId);
+
@EnforcePermission("MANAGE_COMPANION_DEVICES")
void enableSecureTransport(boolean enabled);
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index d41df4f..7b874cc 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -77,6 +77,16 @@
/** One of the values returned by {@link #getSqlStatementType(String)}. */
public static final int STATEMENT_OTHER = 99;
+ // The following statement types are "extended" and are for internal use only. These types
+ // are not public and are never returned by {@link #getSqlStatementType(String)}.
+
+ /** An internal statement type @hide **/
+ public static final int STATEMENT_WITH = 100;
+ /** An internal statement type @hide **/
+ public static final int STATEMENT_CREATE = 101;
+ /** An internal statement type denoting a comment. @hide **/
+ public static final int STATEMENT_COMMENT = 102;
+
/**
* Special function for writing an exception result at the header of
* a parcel, to be used when returning an exception from a transaction.
@@ -1564,6 +1574,79 @@
}
/**
+ * The legacy prefix matcher.
+ */
+ private static String getSqlStatementPrefixSimple(@NonNull String sql) {
+ sql = sql.trim();
+ if (sql.length() < 3) {
+ return null;
+ }
+ return sql.substring(0, 3).toUpperCase(Locale.ROOT);
+ }
+
+ /**
+ * Return the extended statement type for the SQL statement. This is not a public API and it
+ * can return values that are not publicly visible.
+ * @hide
+ */
+ private static int categorizeStatement(@NonNull String prefix, @NonNull String sql) {
+ if (prefix == null) return STATEMENT_OTHER;
+
+ switch (prefix) {
+ case "SEL": return STATEMENT_SELECT;
+ case "INS":
+ case "UPD":
+ case "REP":
+ case "DEL": return STATEMENT_UPDATE;
+ case "ATT": return STATEMENT_ATTACH;
+ case "COM":
+ case "END": return STATEMENT_COMMIT;
+ case "ROL":
+ if (sql.toUpperCase(Locale.ROOT).contains(" TO ")) {
+ // Rollback to savepoint.
+ return STATEMENT_OTHER;
+ }
+ return STATEMENT_ABORT;
+ case "BEG": return STATEMENT_BEGIN;
+ case "PRA": return STATEMENT_PRAGMA;
+ case "CRE": return STATEMENT_CREATE;
+ case "DRO":
+ case "ALT": return STATEMENT_DDL;
+ case "ANA":
+ case "DET": return STATEMENT_UNPREPARED;
+ case "WIT": return STATEMENT_WITH;
+ default:
+ if (prefix.startsWith("--") || prefix.startsWith("/*")) {
+ return STATEMENT_COMMENT;
+ }
+ return STATEMENT_OTHER;
+ }
+ }
+
+ /**
+ * Return the extended statement type for the SQL statement. This is not a public API and it
+ * can return values that are not publicly visible.
+ * @hide
+ */
+ public static int getSqlStatementTypeExtended(@NonNull String sql) {
+ int type = categorizeStatement(getSqlStatementPrefixSimple(sql), sql);
+ return type;
+ }
+
+ /**
+ * Convert an extended statement type to a public SQL statement type value.
+ * @hide
+ */
+ public static int getSqlStatementType(int extended) {
+ switch (extended) {
+ case STATEMENT_CREATE: return STATEMENT_DDL;
+ case STATEMENT_WITH: return STATEMENT_OTHER;
+ case STATEMENT_COMMENT: return STATEMENT_OTHER;
+ }
+ return extended;
+ }
+
+ /**
* Returns one of the following which represent the type of the given SQL statement.
* <ol>
* <li>{@link #STATEMENT_SELECT}</li>
@@ -1572,49 +1655,16 @@
* <li>{@link #STATEMENT_BEGIN}</li>
* <li>{@link #STATEMENT_COMMIT}</li>
* <li>{@link #STATEMENT_ABORT}</li>
+ * <li>{@link #STATEMENT_PRAGMA}</li>
+ * <li>{@link #STATEMENT_DDL}</li>
+ * <li>{@link #STATEMENT_UNPREPARED}</li>
* <li>{@link #STATEMENT_OTHER}</li>
* </ol>
* @param sql the SQL statement whose type is returned by this method
* @return one of the values listed above
*/
public static int getSqlStatementType(String sql) {
- sql = sql.trim();
- if (sql.length() < 3) {
- return STATEMENT_OTHER;
- }
- String prefixSql = sql.substring(0, 3).toUpperCase(Locale.ROOT);
- if (prefixSql.equals("SEL")) {
- return STATEMENT_SELECT;
- } else if (prefixSql.equals("INS") ||
- prefixSql.equals("UPD") ||
- prefixSql.equals("REP") ||
- prefixSql.equals("DEL")) {
- return STATEMENT_UPDATE;
- } else if (prefixSql.equals("ATT")) {
- return STATEMENT_ATTACH;
- } else if (prefixSql.equals("COM")) {
- return STATEMENT_COMMIT;
- } else if (prefixSql.equals("END")) {
- return STATEMENT_COMMIT;
- } else if (prefixSql.equals("ROL")) {
- boolean isRollbackToSavepoint = sql.toUpperCase(Locale.ROOT).contains(" TO ");
- if (isRollbackToSavepoint) {
- Log.w(TAG, "Statement '" + sql
- + "' may not work on API levels 16-27, use ';" + sql + "' instead");
- return STATEMENT_OTHER;
- }
- return STATEMENT_ABORT;
- } else if (prefixSql.equals("BEG")) {
- return STATEMENT_BEGIN;
- } else if (prefixSql.equals("PRA")) {
- return STATEMENT_PRAGMA;
- } else if (prefixSql.equals("CRE") || prefixSql.equals("DRO") ||
- prefixSql.equals("ALT")) {
- return STATEMENT_DDL;
- } else if (prefixSql.equals("ANA") || prefixSql.equals("DET")) {
- return STATEMENT_UNPREPARED;
- }
- return STATEMENT_OTHER;
+ return getSqlStatementType(getSqlStatementTypeExtended(sql));
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index f2980f4..b96d832 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -1096,7 +1096,7 @@
seqNum = mPreparedStatementCache.getLastSeqNum();
try {
final int numParameters = nativeGetParameterCount(mConnectionPtr, statementPtr);
- final int type = DatabaseUtils.getSqlStatementType(sql);
+ final int type = DatabaseUtils.getSqlStatementTypeExtended(sql);
final boolean readOnly = nativeIsReadOnly(mConnectionPtr, statementPtr);
statement = obtainPreparedStatement(sql, statementPtr, numParameters, type, readOnly,
seqNum);
@@ -1279,7 +1279,8 @@
private static boolean isCacheable(int statementType) {
if (statementType == DatabaseUtils.STATEMENT_UPDATE
- || statementType == DatabaseUtils.STATEMENT_SELECT) {
+ || statementType == DatabaseUtils.STATEMENT_SELECT
+ || statementType == DatabaseUtils.STATEMENT_WITH) {
return true;
}
return false;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7967db6..582c5c0 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -685,12 +685,7 @@
private ImeTracker.Token mCurStatsToken;
final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> {
- Log.i("b/297000797", "IME#OnComputeInternalInsetsListener, start info: " + info
- + " before onComputeInsets, tmpInsets: " + mTmpInsets,
- new Throwable());
onComputeInsets(mTmpInsets);
- Log.i("b/297000797", "IME#OnComputeInternalInsetsListener,"
- + " after onComputeInsets, tmpInsets: " + mTmpInsets);
if (!mViewsCreated) {
// The IME views are not ready, keep visible insets untouched.
mTmpInsets.visibleTopInsets = 0;
@@ -710,7 +705,6 @@
}
mNavigationBarController.updateTouchableInsets(mTmpInsets, info);
- Log.i("b/297000797", "IME#OnComputeInternalInsetsListener, end info: " + info);
if (mInputFrame != null) {
setImeExclusionRect(mTmpInsets.visibleTopInsets);
}
@@ -1469,15 +1463,6 @@
proto.write(TOUCHABLE_REGION, touchableRegion.toString());
proto.end(token);
}
-
- @Override
- public String toString() {
- return "Insets{contentTopInsets=" + contentTopInsets
- + " visibleTopInsets=" + visibleTopInsets
- + " touchableInsets=" + touchableInsets
- + " touchableRegion=" + touchableRegion.getBounds()
- + "}";
- }
}
/**
@@ -4154,13 +4139,13 @@
p.println(" mExtractedToken=" + mExtractedToken);
p.println(" mIsInputViewShown=" + mIsInputViewShown
+ " mStatusIcon=" + mStatusIcon);
- p.println("Last computed insets:");
- p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets
+ p.println(" Last computed insets:");
+ p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets
+ " visibleTopInsets=" + mTmpInsets.visibleTopInsets
+ " touchableInsets=" + mTmpInsets.touchableInsets
+ " touchableRegion=" + mTmpInsets.touchableRegion);
- p.println(" mSettingsObserver=" + mSettingsObserver);
- p.println(" mNavigationBarController=" + mNavigationBarController.toDebugString());
+ p.println(" mSettingsObserver=" + mSettingsObserver);
+ p.println(" mNavigationBarController=" + mNavigationBarController.toDebugString());
}
private final ImeTracing.ServiceDumper mDumper = new ImeTracing.ServiceDumper() {
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 22792a5..8be4c58 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -31,7 +31,6 @@
import android.graphics.Region;
import android.inputmethodservice.navigationbar.NavigationBarFrame;
import android.inputmethodservice.navigationbar.NavigationBarView;
-import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -115,8 +114,6 @@
}
void onNavButtonFlagsChanged(@InputMethodNavButtonFlags int navButtonFlags) {
- Log.i("b/297000797", "NavigationBarController#onNavButtonFlagsChanged: " + navButtonFlags,
- new Throwable());
mImpl.onNavButtonFlagsChanged(navButtonFlags);
}
@@ -238,10 +235,6 @@
if (ENABLE_HIDE_IME_CAPTION_BAR) {
mNavigationBarFrame.setOnApplyWindowInsetsListener((view, insets) -> {
- Log.i("b/297000797", "NavigationBarController#onApplyWindowInsetsListener:"
- + " mNavigationBarFrame: " + mNavigationBarFrame
- + " captionBar visible: " + insets.isVisible(captionBar())
- + " insets: " + insets);
if (mNavigationBarFrame != null) {
boolean visible = insets.isVisible(captionBar());
mNavigationBarFrame.setVisibility(visible ? View.VISIBLE : View.GONE);
@@ -460,10 +453,6 @@
mShouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherWhenImeIsShown;
if (ENABLE_HIDE_IME_CAPTION_BAR) {
- Log.i("b/297000797", "NavigationBarController#onNavButtonFlagsChanged,"
- + " calling setImeCaptionBarInsetsHeight"
- + " with: " + getImeCaptionBarHeight(),
- new Throwable());
mService.mWindow.getWindow().getDecorView().getWindowInsetsController()
.setImeCaptionBarInsetsHeight(getImeCaptionBarHeight());
}
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 851aa6d..febe6f7 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -6,3 +6,17 @@
description: "Guards a new UserManager user restriction that admins can use to require cellular encryption on their managed devices."
bug: "276752881"
}
+
+flag {
+ name: "remove_app_profiler_pss_collection"
+ namespace: "android_platform_power_optimization"
+ description: "Replaces background PSS collection in AppProfiler with RSS"
+ bug: "297542292"
+}
+
+flag {
+ name: "allow_private_profile"
+ namespace: "private_profile"
+ description: "Guards a new Private Profile type in UserManager - everything from its setup to config to deletion."
+ bug: "299069460"
+}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 637770c..04ae0af 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -2556,7 +2556,7 @@
private void doDetachEngine() {
// Some wallpapers will not trigger the rendering threads of the remaining engines even
// if they are visible, so we need to toggle the state to get their attention.
- if (!mEngine.mDestroyed) {
+ if (mEngine != null && !mEngine.mDestroyed) {
mEngine.detach();
synchronized (mActiveEngines) {
for (IWallpaperEngineWrapper engineWrapper : mActiveEngines.values()) {
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 2761aae..bc83750 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -35,6 +35,8 @@
* @hide
*/
public final class InputWindowHandle {
+ // TODO (b/300094445): Convert to use correct flagging infrastructure
+ public static final boolean USE_SURFACE_TRUSTED_OVERLAY = true;
/**
* An internal annotation for all the {@link android.os.InputConfig} flags that can be
@@ -59,7 +61,6 @@
InputConfig.DUPLICATE_TOUCH_TO_WALLPAPER,
InputConfig.IS_WALLPAPER,
InputConfig.PAUSE_DISPATCHING,
- InputConfig.TRUSTED_OVERLAY,
InputConfig.WATCH_OUTSIDE_TOUCH,
InputConfig.SLIPPERY,
InputConfig.DISABLE_USER_ACTIVITY,
@@ -272,4 +273,13 @@
}
this.inputConfig &= ~inputConfig;
}
+
+ public void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc,
+ boolean isTrusted) {
+ if (USE_SURFACE_TRUSTED_OVERLAY) {
+ t.setTrustedOverlay(sc, isTrusted);
+ } else if (isTrusted) {
+ inputConfig |= InputConfig.TRUSTED_OVERLAY;
+ }
+ }
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 9186e49..fb24211 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1856,8 +1856,6 @@
return;
}
Rect newFrame = new Rect(mFrame.left, mFrame.bottom - height, mFrame.right, mFrame.bottom);
- Log.i("b/297000797", "InsetsController#setImeCaptionBarInsetsHeight,"
- + " height: " + height + " frame: " + mFrame);
InsetsSource source = mState.peekSource(ID_IME_CAPTION_BAR);
if (mImeCaptionBarInsetsHeight != height
|| (source != null && !newFrame.equals(source.getFrame()))) {
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 3e435ae..0d5704e 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -31,7 +31,6 @@
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.WindowInsets.Type.InsetsType;
@@ -197,12 +196,6 @@
* source.
*/
public Insets calculateInsets(Rect relativeFrame, boolean ignoreVisibility) {
- if (getType() == WindowInsets.Type.ime()) {
- Log.i("b/297000797", "InsetsSource#calculateInsets tmpFrame: " + mTmpFrame
- + " ignoreVisibility: " + ignoreVisibility
- + " frame: " + mFrame
- + " relativeFrame: " + relativeFrame, new Throwable());
- }
return calculateInsets(relativeFrame, mFrame, ignoreVisibility);
}
@@ -210,12 +203,6 @@
* Like {@link #calculateInsets(Rect, boolean)}, but will return visible insets.
*/
public Insets calculateVisibleInsets(Rect relativeFrame) {
- if (getType() == WindowInsets.Type.ime()) {
- Log.i("b/297000797", "InsetsSource#calculateVisibleInsets tmpFrame: " + mTmpFrame
- + " frame: " + mFrame
- + " visibleFrame: " + mVisibleFrame
- + " relativeFrame: " + relativeFrame, new Throwable());
- }
return calculateInsets(relativeFrame, mVisibleFrame != null ? mVisibleFrame : mFrame,
false /* ignoreVisibility */);
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index eac7408..59e0932 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -45,7 +45,6 @@
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
@@ -381,9 +380,6 @@
@InternalInsetsSide @Nullable SparseIntArray idSideMap,
@Nullable boolean[] typeVisibilityMap, Insets insets, int type) {
int index = indexOf(type);
- if (source.getId() == InsetsSource.ID_IME) {
- Log.i("b/297000797", "InsetsState#processSourceAsPublicType, ime insets: " + insets);
- }
// Don't put Insets.NONE into typeInsetsMap. Otherwise, two WindowInsets can be considered
// as non-equal while they provide the same insets of each type from WindowInsets#getInsets
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 9e8ca20..c9526fd 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -315,15 +315,6 @@
}
@Override
- public String toString() {
- return "InternalInsetsInfo{contentInsets=" + contentInsets
- + " visibleInsets=" + visibleInsets
- + " touchableRegion=" + touchableRegion.getBounds()
- + "}";
-
- }
-
- @Override
public int hashCode() {
int result = contentInsets.hashCode();
result = 31 * result + visibleInsets.hashCode();
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
new file mode 100644
index 0000000..f1d981a
--- /dev/null
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.window.flags"
+
+flag {
+ name: "letterbox_background_wallpaper_flag"
+ namespace: "large_screen_experiences_app_compat"
+ description: "Whether the letterbox wallpaper style is enabled by default"
+ bug: "297195682"
+}
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index 5e2eceb..dee4935 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -177,7 +177,7 @@
* <code>1</code> would return the work profile {@link ProfileDescriptor}.</li>
* </ul>
*/
- abstract ProfileDescriptor getItem(int pageIndex);
+ public abstract ProfileDescriptor getItem(int pageIndex);
/**
* Returns the number of {@link ProfileDescriptor} objects.
@@ -438,8 +438,8 @@
&& isQuietModeEnabled(mWorkProfileUserHandle));
}
- protected class ProfileDescriptor {
- final ViewGroup rootView;
+ public static class ProfileDescriptor {
+ public final ViewGroup rootView;
private final ViewGroup mEmptyStateView;
ProfileDescriptor(ViewGroup rootView) {
this.rootView = rootView;
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 7beb059..8197e26 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -94,7 +94,7 @@
}
@Override
- ChooserProfileDescriptor getItem(int pageIndex) {
+ public ChooserProfileDescriptor getItem(int pageIndex) {
return mItems[pageIndex];
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ac15f11..7534d29 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -2623,13 +2623,13 @@
* An a11y delegate that expands resolver drawer when gesture navigation reaches a partially
* invisible target in the list.
*/
- private static class AppListAccessibilityDelegate extends View.AccessibilityDelegate {
+ public static class AppListAccessibilityDelegate extends View.AccessibilityDelegate {
private final ResolverDrawerLayout mDrawer;
@Nullable
private final View mBottomBar;
private final Rect mRect = new Rect();
- private AppListAccessibilityDelegate(ResolverDrawerLayout drawer) {
+ public AppListAccessibilityDelegate(ResolverDrawerLayout drawer) {
mDrawer = drawer;
mBottomBar = mDrawer.findViewById(R.id.button_bar_container);
}
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index 7677912..031f9d3 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -79,7 +79,7 @@
}
@Override
- ResolverProfileDescriptor getItem(int pageIndex) {
+ public ResolverProfileDescriptor getItem(int pageIndex) {
return mItems[pageIndex];
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 1ed06b4..1bfb51c 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -70,7 +70,6 @@
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_CLEAR_ALL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_DIALOG_OPEN;
-import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_FROM_STATUS_BAR;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_APPEAR;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_DISAPPEAR;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_ADD;
@@ -269,7 +268,6 @@
* eg: Exit the app using back gesture.
*/
public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK = 78;
- public static final int CUJ_SHADE_EXPAND_FROM_STATUS_BAR = 79;
public static final int CUJ_IME_INSETS_SHOW_ANIMATION = 80;
public static final int CUJ_IME_INSETS_HIDE_ANIMATION = 81;
@@ -364,7 +362,7 @@
CUJ_TO_STATSD_INTERACTION_TYPE[76] = NO_STATSD_LOGGING;
CUJ_TO_STATSD_INTERACTION_TYPE[77] = NO_STATSD_LOGGING;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK;
- CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SHADE_EXPAND_FROM_STATUS_BAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_FROM_STATUS_BAR;
+ CUJ_TO_STATSD_INTERACTION_TYPE[79] = NO_STATSD_LOGGING; // This is deprecated.
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_SHOW_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_SHOW_ANIMATION;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_HIDE_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_HIDE_ANIMATION;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_DOUBLE_TAP_DIVIDER;
@@ -467,7 +465,6 @@
CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION,
CUJ_LAUNCHER_OPEN_SEARCH_RESULT,
CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK,
- CUJ_SHADE_EXPAND_FROM_STATUS_BAR,
CUJ_IME_INSETS_SHOW_ANIMATION,
CUJ_IME_INSETS_HIDE_ANIMATION,
CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER,
@@ -1082,8 +1079,6 @@
return "LAUNCHER_OPEN_SEARCH_RESULT";
case CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK:
return "LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK";
- case CUJ_SHADE_EXPAND_FROM_STATUS_BAR:
- return "SHADE_EXPAND_FROM_STATUS_BAR";
case CUJ_IME_INSETS_SHOW_ANIMATION:
return "IME_INSETS_SHOW_ANIMATION";
case CUJ_IME_INSETS_HIDE_ANIMATION:
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 9d66174..3e16df4d 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1123,7 +1123,6 @@
final Insets systemInsets = clearsCompatInsets
? Insets.NONE
: Insets.min(insets.getInsets(compatInsetsTypes), stableBarInsets);
- Log.i("b/297000797", "DecorView#updateColorViews, systemInsets: " + systemInsets);
mLastTopInset = systemInsets.top;
mLastBottomInset = systemInsets.bottom;
mLastRightInset = systemInsets.right;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 9b9e010..9b5a3f7 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -333,6 +333,8 @@
private long mBackgroundFadeDurationMillis = -1;
private Boolean mSharedElementsUseOverlay;
+ private Boolean mAllowFloatingWindowsFillScreen;
+
private boolean mIsStartingWindow;
private int mTheme = -1;
@@ -361,6 +363,8 @@
mRenderShadowsInCompositor = Settings.Global.getInt(context.getContentResolver(),
DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
mProxyOnBackInvokedDispatcher = new ProxyOnBackInvokedDispatcher(context);
+ mAllowFloatingWindowsFillScreen = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_allowFloatingWindowsFillScreen);
}
/**
@@ -2422,7 +2426,7 @@
mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
& (~getForcedWindowFlags());
- if (mIsFloating) {
+ if (mIsFloating && !mAllowFloatingWindowsFillScreen) {
setLayout(WRAP_CONTENT, WRAP_CONTENT);
setFlags(0, flagsToUpdate);
} else {
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index b0d9b67..5319762 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -77,4 +77,8 @@
<!-- Default hyphenation frequency setting (0=NONE, 1=NORMAL, 2=FULL). -->
<item name="config_preferredHyphenationFrequency" format="integer" type="dimen">1</item>
+
+ <!-- Floating windows can be fullscreen (i.e. windowIsFloating can still have fullscreen
+ window that does not wrap content). -->
+ <bool name="config_allowFloatingWindowsFillScreen">true</bool>
</resources>
diff --git a/core/res/res/values-watch/dimens_material.xml b/core/res/res/values-watch/dimens_material.xml
index 40673c1..2ab2d91 100644
--- a/core/res/res/values-watch/dimens_material.xml
+++ b/core/res/res/values-watch/dimens_material.xml
@@ -58,4 +58,7 @@
<dimen name="screen_percentage_10">0dp</dimen>
<dimen name="screen_percentage_12">0dp</dimen>
<dimen name="screen_percentage_15">0dp</dimen>
+
+ <!-- dialog elevation [overrides 18dp] -->
+ <dimen name="floating_window_z">2dp</dimen>
</resources>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index c4c1ed9..df8158d 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -52,6 +52,7 @@
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
<style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Material.NoActionBar">
+ <item name="android:windowActionBar">false</item>
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -70,6 +71,8 @@
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
sets {@link android.R.attr#windowFullscreen} to true. -->
<style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowActionBar">false</item>
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -90,6 +93,7 @@
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
to true. -->
<style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan">
+ <item name="android:windowActionBar">false</item>
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -149,8 +153,8 @@
watch theme is not floating. You can set this theme on an activity if you would like to make
an activity that looks like a Dialog.-->
<style name="Theme.DeviceDefault.Dialog" parent="Theme.Material.Dialog" >
- <item name="windowIsFloating">false</item>
- <item name="windowElevation">0dp</item>
+ <item name="android:windowFullscreen">true</item>
+
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
<item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
@@ -175,6 +179,23 @@
<item name="secondaryContentAlpha">@dimen/secondary_content_alpha_device_default</item>
</style>
+ <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
+ <item name="android:windowFullscreen">true</item>
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorForeground">@color/foreground_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ <item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="disabledAlpha">@dimen/disabled_alpha_device_default</item>
+ <item name="primaryContentAlpha">@dimen/primary_content_alpha_device_default</item>
+ <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_device_default</item>
+ </style>
+
<!-- DeviceDefault theme for a window that should look like the Settings app. -->
<style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault"/>
<style name="Theme.DeviceDefault.Settings.NoActionBar" parent="Theme.DeviceDefault"/>
@@ -185,9 +206,9 @@
<style name="Theme.DeviceDefault.Settings.Dialog.Presentation" parent="Theme.DeviceDefault.Dialog.Presentation"/>
<style name="Theme.DeviceDefault.Settings.SearchBar" parent="Theme.DeviceDefault.SearchBar"/>
- <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
- <item name="windowIsFloating">false</item>
- <item name="windowElevation">0dp</item>
+ <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.DeviceDefault.Dialog.Alert">
+ <item name="android:windowFullscreen">true</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -204,8 +225,6 @@
</style>
<style name="Theme.DeviceDefault.Settings.CompactMenu" parent="Theme.Material.CompactMenu">
- <item name="windowIsFloating">false</item>
- <item name="windowElevation">0dp</item>
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -224,8 +243,7 @@
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
regular dialog. -->
<style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth">
- <item name="windowIsFloating">false</item>
- <item name="windowElevation">0dp</item>
+ <item name="android:windowFullscreen">true</item>
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -243,8 +261,8 @@
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
<style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar">
- <item name="windowIsFloating">false</item>
- <item name="windowElevation">0dp</item>
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowActionBar">false</item>
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -263,8 +281,8 @@
<!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
for a regular dialog. -->
<style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth">
- <item name="windowIsFloating">false</item>
- <item name="windowElevation">0dp</item>
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowActionBar">false</item>
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -302,6 +320,8 @@
full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
xlarge). -->
<style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowActionBar">false</item>
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -319,6 +339,7 @@
<!-- DeviceDefault theme for a presentation window on a secondary display. -->
<style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation">
+ <item name="android:windowFullscreen">true</item>
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -338,6 +359,8 @@
decorations, so you basically have an empty rectangle in which to place your content. It makes
the window floating, with a transparent background, and turns off dimming behind the window. -->
<style name="Theme.DeviceDefault.Panel" parent="Theme.Material.Panel">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowActionBar">false</item>
<!-- Color palette Dark -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -407,24 +430,6 @@
<item name="secondaryContentAlpha">@dimen/secondary_content_alpha_device_default</item>
</style>
- <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
- <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
-
- <!-- Color palette Dialog -->
- <item name="colorPrimary">@color/primary_device_default_dark</item>
- <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
- <item name="colorForeground">@color/foreground_device_default_dark</item>
- <item name="colorAccent">@color/accent_device_default_dark</item>
- <item name="colorBackground">@color/background_device_default_dark</item>
- <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
- <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
- <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
- <item name="colorError">@color/error_color_device_default_dark</item>
- <item name="disabledAlpha">@dimen/disabled_alpha_device_default</item>
- <item name="primaryContentAlpha">@dimen/primary_content_alpha_device_default</item>
- <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_device_default</item>
- </style>
-
<!-- Theme for the dialog shown when an app crashes or ANRs. Override to make it dark. -->
<style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert">
<item name="alertDialogStyle">@style/BaseErrorDialog.DeviceDefault</item>
@@ -451,8 +456,6 @@
</style>
<style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
- <item name="windowIsFloating">false</item>
- <item name="windowElevation">0dp</item>
<!-- Color palette Dialog -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
diff --git a/core/res/res/values-watch/themes_material.xml b/core/res/res/values-watch/themes_material.xml
index 40a249a..674b3bc 100644
--- a/core/res/res/values-watch/themes_material.xml
+++ b/core/res/res/values-watch/themes_material.xml
@@ -42,26 +42,31 @@
<!-- Override behaviour to set the theme colours for dialogs, keep them the same. -->
<style name="ThemeOverlay.Material.Dialog" parent="ThemeOverlay.Material.BaseDialog">
- <item name="windowIsFloating">false</item>
- <item name="windowElevation">0dp</item>
+ <item name="android:windowFullscreen">true</item>
</style>
<!-- Force the background and floating colours to be the default colours. -->
<style name="Theme.Material.Dialog" parent="Theme.Material.BaseDialog">
+ <item name="android:windowFullscreen">true</item>
<item name="colorBackground">@color/background_material_dark</item>
<item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
<item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
- <item name="windowIsFloating">false</item>
- <item name="windowElevation">0dp</item>
+ </style>
+
+ <!-- Force the background and floating colours to be the default colours. -->
+ <style name="Theme.Material.Dialog.Alert" parent="Theme.Material.Dialog.BaseAlert">
+ <item name="android:windowFullscreen">true</item>
+ <item name="colorBackground">@color/background_material_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
</style>
<!-- Force the background and floating colours to be the default colours. -->
<style name="Theme.Material.Light.Dialog" parent="Theme.Material.Light.BaseDialog">
+ <item name="android:windowFullscreen">true</item>
<item name="colorBackground">@color/background_material_light</item>
<item name="colorBackgroundFloating">@color/background_floating_material_light</item>
<item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
- <item name="windowIsFloating">false</item>
- <item name="windowElevation">0dp</item>
</style>
<!-- Force all settings themes to use normal Material theme. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e7764d8..d09bf44 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6699,6 +6699,10 @@
<!-- Whether unlocking and waking a device are sequenced -->
<bool name="config_orderUnlockAndWake">false</bool>
+ <!-- Floating windows can be fullscreen (i.e. windowIsFloating can still have fullscreen
+ window that does not wrap content). -->
+ <bool name="config_allowFloatingWindowsFillScreen">false</bool>
+
<!-- Whether scroll haptic feedback is enabled for rotary encoder scrolls on
{@link MotionEvent#AXIS_SCROLL} generated by {@link InputDevice#SOURCE_ROTARY_ENCODER}
devices. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 80c2fbf..7f1a6f9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5226,6 +5226,9 @@
<!-- Whether we order unlocking and waking -->
<java-symbol type="bool" name="config_orderUnlockAndWake" />
+ <!-- Allow windowIsFloating to fill screen. -->
+ <java-symbol type="bool" name="config_allowFloatingWindowsFillScreen" />
+
<!-- External TV Input Logging Configs -->
<java-symbol type="bool" name="config_tvExternalInputLoggingDisplayNameFilterEnabled" />
<java-symbol type="array" name="config_tvExternalInputLoggingDeviceOnScreenDisplayNames" />
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 819178f..8935507 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -245,7 +245,7 @@
newConfig.smallestScreenWidthDp++;
transaction = newTransaction(activityThread, activity.getActivityToken());
transaction.addCallback(ActivityConfigurationChangeItem.obtain(
- new Configuration(newConfig)));
+ activity.getActivityToken(), new Configuration(newConfig)));
appThread.scheduleTransaction(transaction);
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -450,10 +450,12 @@
appThread.scheduleTransaction(transaction);
transaction = newTransaction(activityThread, activity.getActivityToken());
- transaction.addCallback(ActivityConfigurationChangeItem.obtain(activityConfigLandscape));
+ transaction.addCallback(ActivityConfigurationChangeItem.obtain(
+ activity.getActivityToken(), activityConfigLandscape));
transaction.addCallback(ConfigurationChangeItem.obtain(
processConfigPortrait, DEVICE_ID_INVALID));
- transaction.addCallback(ActivityConfigurationChangeItem.obtain(activityConfigPortrait));
+ transaction.addCallback(ActivityConfigurationChangeItem.obtain(
+ activity.getActivityToken(), activityConfigPortrait));
appThread.scheduleTransaction(transaction);
activity.mTestLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
@@ -829,11 +831,12 @@
private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
final Configuration currentConfig = activity.getResources().getConfiguration();
- final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
- null, 0, new MergedConfiguration(currentConfig, currentConfig),
+ final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(
+ activity.getActivityToken(), null, null, 0,
+ new MergedConfiguration(currentConfig, currentConfig),
false /* preserveWindow */);
final ResumeActivityItem resumeStateRequest =
- ResumeActivityItem.obtain(true /* isForward */,
+ ResumeActivityItem.obtain(activity.getActivityToken(), true /* isForward */,
false /* shouldSendCompatFakeFocus*/);
final ClientTransaction transaction = newTransaction(activity);
@@ -845,7 +848,7 @@
private static ClientTransaction newResumeTransaction(Activity activity) {
final ResumeActivityItem resumeStateRequest =
- ResumeActivityItem.obtain(true /* isForward */,
+ ResumeActivityItem.obtain(activity.getActivityToken(), true /* isForward */,
false /* shouldSendCompatFakeFocus */);
final ClientTransaction transaction = newTransaction(activity);
@@ -855,7 +858,8 @@
}
private static ClientTransaction newStopTransaction(Activity activity) {
- final StopActivityItem stopStateRequest = StopActivityItem.obtain(0 /* configChanges */);
+ final StopActivityItem stopStateRequest = StopActivityItem.obtain(
+ activity.getActivityToken(), 0 /* configChanges */);
final ClientTransaction transaction = newTransaction(activity);
transaction.setLifecycleStateRequest(stopStateRequest);
@@ -865,7 +869,8 @@
private static ClientTransaction newActivityConfigTransaction(Activity activity,
Configuration config) {
- final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config);
+ final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(
+ activity.getActivityToken(), config);
final ClientTransaction transaction = newTransaction(activity);
transaction.addCallback(item);
@@ -875,7 +880,8 @@
private static ClientTransaction newNewIntentTransaction(Activity activity,
List<ReferrerIntent> intents, boolean resume) {
- final NewIntentItem item = NewIntentItem.obtain(intents, resume);
+ final NewIntentItem item = NewIntentItem.obtain(activity.getActivityToken(), intents,
+ resume);
final ClientTransaction transaction = newTransaction(activity);
transaction.addCallback(item);
diff --git a/core/tests/coretests/src/android/app/servertransaction/ActivityConfigurationChangeItemTest.java b/core/tests/coretests/src/android/app/servertransaction/ActivityConfigurationChangeItemTest.java
index 1560c0c..08033cc 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ActivityConfigurationChangeItemTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ActivityConfigurationChangeItemTest.java
@@ -65,7 +65,7 @@
doReturn(mActivity).when(mHandler).getActivity(mToken);
final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem
- .obtain(mConfiguration);
+ .obtain(mToken, mConfiguration);
final Context context = item.getContextToUpdate(mHandler, mToken);
assertEquals(mActivity, context);
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index ca6735b..c8d8f4b 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -22,7 +22,6 @@
import static android.app.servertransaction.TestUtils.resultInfoList;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
@@ -61,39 +60,44 @@
@Presubmit
public class ObjectPoolTests {
+ private final IBinder mActivityToken = new Binder();
+
// 1. Check if two obtained objects from pool are not the same.
// 2. Check if the state of the object is cleared after recycling.
// 3. Check if the same object is obtained from pool after recycling.
@Test
public void testRecycleActivityConfigurationChangeItem() {
- ActivityConfigurationChangeItem emptyItem =
- ActivityConfigurationChangeItem.obtain(Configuration.EMPTY);
- ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config());
+ ActivityConfigurationChangeItem emptyItem = ActivityConfigurationChangeItem.obtain(
+ null /* activityToken */, Configuration.EMPTY);
+ ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(
+ mActivityToken, config());
assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
+ assertNotEquals(item, emptyItem);
item.recycle();
assertEquals(item, emptyItem);
- ActivityConfigurationChangeItem item2 = ActivityConfigurationChangeItem.obtain(config());
+ ActivityConfigurationChangeItem item2 = ActivityConfigurationChangeItem.obtain(
+ mActivityToken, config());
assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
+ assertNotEquals(item2, emptyItem);
}
@Test
public void testRecycleActivityResultItem() {
- ActivityResultItem emptyItem = ActivityResultItem.obtain(null);
- ActivityResultItem item = ActivityResultItem.obtain(resultInfoList());
+ ActivityResultItem emptyItem = ActivityResultItem.obtain(
+ null /* activityToken */, null /* resultInfoList */);
+ ActivityResultItem item = ActivityResultItem.obtain(mActivityToken, resultInfoList());
assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
+ assertNotEquals(item, emptyItem);
item.recycle();
assertEquals(item, emptyItem);
- ActivityResultItem item2 = ActivityResultItem.obtain(resultInfoList());
+ ActivityResultItem item2 = ActivityResultItem.obtain(mActivityToken, resultInfoList());
assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
+ assertNotEquals(item2, emptyItem);
}
@Test
@@ -101,166 +105,188 @@
ConfigurationChangeItem emptyItem = ConfigurationChangeItem.obtain(null, 0);
ConfigurationChangeItem item = ConfigurationChangeItem.obtain(config(), 1);
assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
+ assertNotEquals(item, emptyItem);
item.recycle();
assertEquals(item, emptyItem);
ConfigurationChangeItem item2 = ConfigurationChangeItem.obtain(config(), 1);
assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
+ assertNotEquals(item2, emptyItem);
}
@Test
public void testRecycleDestroyActivityItem() {
- DestroyActivityItem emptyItem = DestroyActivityItem.obtain(false, 0);
- DestroyActivityItem item = DestroyActivityItem.obtain(true, 117);
- assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
-
- item.recycle();
- assertEquals(item, emptyItem);
-
- DestroyActivityItem item2 = DestroyActivityItem.obtain(true, 14);
- assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
- }
-
- @Test
- public void testRecycleLaunchActivityItem() {
- Intent intent = new Intent("action");
- int ident = 57;
- ActivityInfo activityInfo = new ActivityInfo();
- activityInfo.flags = 42;
- activityInfo.setMaxAspectRatio(2.4f);
- activityInfo.launchToken = "token";
- activityInfo.applicationInfo = new ApplicationInfo();
- activityInfo.packageName = "packageName";
- activityInfo.name = "name";
- Configuration overrideConfig = new Configuration();
- overrideConfig.assetsSeq = 5;
- String referrer = "referrer";
- int procState = 4;
- Bundle bundle = new Bundle();
- bundle.putString("key", "value");
- PersistableBundle persistableBundle = new PersistableBundle();
- persistableBundle.putInt("k", 4);
- IBinder assistToken = new Binder();
- IBinder shareableActivityToken = new Binder();
- int deviceId = 3;
-
- Supplier<LaunchActivityItem> itemSupplier = () -> new LaunchActivityItemBuilder()
- .setIntent(intent).setIdent(ident).setInfo(activityInfo).setCurConfig(config())
- .setOverrideConfig(overrideConfig).setReferrer(referrer)
- .setProcState(procState).setState(bundle).setPersistentState(persistableBundle)
- .setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList())
- .setIsForward(true).setAssistToken(assistToken)
- .setShareableActivityToken(shareableActivityToken)
- .setTaskFragmentToken(new Binder()).setDeviceId(deviceId).build();
-
- LaunchActivityItem emptyItem = new LaunchActivityItemBuilder().build();
- LaunchActivityItem item = itemSupplier.get();
- assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
-
- item.recycle();
- assertEquals(item, emptyItem);
-
- LaunchActivityItem item2 = itemSupplier.get();
- assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
- }
-
- @Test
- public void testRecycleActivityRelaunchItem() {
- ActivityRelaunchItem emptyItem = ActivityRelaunchItem.obtain(null, null, 0, null, false);
- Configuration overrideConfig = new Configuration();
- overrideConfig.assetsSeq = 5;
- ActivityRelaunchItem item = ActivityRelaunchItem.obtain(resultInfoList(),
- referrerIntentList(), 42, mergedConfig(), true);
- assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
-
- item.recycle();
- assertEquals(item, emptyItem);
-
- ActivityRelaunchItem item2 = ActivityRelaunchItem.obtain(resultInfoList(),
- referrerIntentList(), 42, mergedConfig(), true);
- assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
- }
-
- @Test
- public void testRecycleMoveToDisplayItem() {
- MoveToDisplayItem emptyItem = MoveToDisplayItem.obtain(0, Configuration.EMPTY);
- MoveToDisplayItem item = MoveToDisplayItem.obtain(4, config());
- assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
-
- item.recycle();
- assertEquals(item, emptyItem);
-
- MoveToDisplayItem item2 = MoveToDisplayItem.obtain(3, config());
- assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
- }
-
- @Test
- public void testRecycleNewIntentItem() {
- NewIntentItem emptyItem = NewIntentItem.obtain(null, false);
- NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), false);
- assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
-
- item.recycle();
- assertEquals(item, emptyItem);
-
- NewIntentItem item2 = NewIntentItem.obtain(referrerIntentList(), false);
- assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
- }
-
- @Test
- public void testRecyclePauseActivityItemItem() {
- PauseActivityItem emptyItem = PauseActivityItem.obtain(false, false, 0, false, false);
- PauseActivityItem item = PauseActivityItem.obtain(true, true, 5, true, true);
- assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
-
- item.recycle();
- assertEquals(item, emptyItem);
-
- PauseActivityItem item2 = PauseActivityItem.obtain(true, false, 5, true, true);
- assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
- }
-
- @Test
- public void testRecycleResumeActivityItem() {
- ResumeActivityItem emptyItem = ResumeActivityItem.obtain(false, false);
- ResumeActivityItem item = ResumeActivityItem.obtain(3, true, false);
- assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
-
- item.recycle();
- assertEquals(item, emptyItem);
-
- ResumeActivityItem item2 = ResumeActivityItem.obtain(2, true, false);
- assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
- }
-
- @Test
- public void testRecycleStartActivityItem() {
- StartActivityItem emptyItem = StartActivityItem.obtain(null /* activityOptions */);
- StartActivityItem item = StartActivityItem.obtain(ActivityOptions.makeBasic());
+ DestroyActivityItem emptyItem = DestroyActivityItem.obtain(
+ null /* activityToken */, false, 0);
+ DestroyActivityItem item = DestroyActivityItem.obtain(mActivityToken, true, 117);
assertNotSame(item, emptyItem);
assertNotEquals(item, emptyItem);
item.recycle();
assertEquals(item, emptyItem);
- StartActivityItem item2 = StartActivityItem.obtain(
+ DestroyActivityItem item2 = DestroyActivityItem.obtain(mActivityToken, true, 14);
+ assertSame(item, item2);
+ assertNotEquals(item2, emptyItem);
+ }
+
+ @Test
+ public void testRecycleLaunchActivityItem() {
+ final IBinder activityToken = new Binder();
+ final Intent intent = new Intent("action");
+ int ident = 57;
+ final ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.flags = 42;
+ activityInfo.setMaxAspectRatio(2.4f);
+ activityInfo.launchToken = "token";
+ activityInfo.applicationInfo = new ApplicationInfo();
+ activityInfo.packageName = "packageName";
+ activityInfo.name = "name";
+ final Configuration overrideConfig = new Configuration();
+ overrideConfig.assetsSeq = 5;
+ final String referrer = "referrer";
+ int procState = 4;
+ final Bundle bundle = new Bundle();
+ bundle.putString("key", "value");
+ final PersistableBundle persistableBundle = new PersistableBundle();
+ persistableBundle.putInt("k", 4);
+ final IBinder assistToken = new Binder();
+ final IBinder shareableActivityToken = new Binder();
+ int deviceId = 3;
+
+ final Supplier<LaunchActivityItem> itemSupplier = () -> new LaunchActivityItemBuilder()
+ .setActivityToken(activityToken)
+ .setIntent(intent)
+ .setIdent(ident)
+ .setInfo(activityInfo)
+ .setCurConfig(config())
+ .setOverrideConfig(overrideConfig)
+ .setReferrer(referrer)
+ .setProcState(procState)
+ .setState(bundle)
+ .setPersistentState(persistableBundle)
+ .setPendingResults(resultInfoList())
+ .setPendingNewIntents(referrerIntentList())
+ .setIsForward(true)
+ .setAssistToken(assistToken)
+ .setShareableActivityToken(shareableActivityToken)
+ .setTaskFragmentToken(new Binder())
+ .setDeviceId(deviceId)
+ .build();
+
+ LaunchActivityItem emptyItem = new LaunchActivityItemBuilder().build();
+ LaunchActivityItem item = itemSupplier.get();
+ assertNotSame(item, emptyItem);
+ assertNotEquals(item, emptyItem);
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ LaunchActivityItem item2 = itemSupplier.get();
+ assertSame(item, item2);
+ assertNotEquals(item2, emptyItem);
+ }
+
+ @Test
+ public void testRecycleActivityRelaunchItem() {
+ ActivityRelaunchItem emptyItem = ActivityRelaunchItem.obtain(
+ null /* activityToken */, null, null, 0, null, false);
+ Configuration overrideConfig = new Configuration();
+ overrideConfig.assetsSeq = 5;
+ ActivityRelaunchItem item = ActivityRelaunchItem.obtain(mActivityToken, resultInfoList(),
+ referrerIntentList(), 42, mergedConfig(), true);
+ assertNotSame(item, emptyItem);
+ assertNotEquals(item, emptyItem);
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ ActivityRelaunchItem item2 = ActivityRelaunchItem.obtain(mActivityToken, resultInfoList(),
+ referrerIntentList(), 42, mergedConfig(), true);
+ assertSame(item, item2);
+ assertNotEquals(item2, emptyItem);
+ }
+
+ @Test
+ public void testRecycleMoveToDisplayItem() {
+ MoveToDisplayItem emptyItem = MoveToDisplayItem.obtain(
+ null /* activityToken */, 0, Configuration.EMPTY);
+ MoveToDisplayItem item = MoveToDisplayItem.obtain(mActivityToken, 4, config());
+ assertNotSame(item, emptyItem);
+ assertNotEquals(item, emptyItem);
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ MoveToDisplayItem item2 = MoveToDisplayItem.obtain(mActivityToken, 3, config());
+ assertSame(item, item2);
+ assertNotEquals(item2, emptyItem);
+ }
+
+ @Test
+ public void testRecycleNewIntentItem() {
+ NewIntentItem emptyItem = NewIntentItem.obtain(
+ null /* activityToken */, null /* intents */, false /* resume */);
+ NewIntentItem item = NewIntentItem.obtain(mActivityToken, referrerIntentList(), false);
+ assertNotSame(item, emptyItem);
+ assertNotEquals(item, emptyItem);
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ NewIntentItem item2 = NewIntentItem.obtain(mActivityToken, referrerIntentList(), false);
+ assertSame(item, item2);
+ assertNotEquals(item2, emptyItem);
+ }
+
+ @Test
+ public void testRecyclePauseActivityItemItem() {
+ PauseActivityItem emptyItem = PauseActivityItem.obtain(
+ null /* activityToken */, false, false, 0, false, false);
+ PauseActivityItem item = PauseActivityItem.obtain(
+ mActivityToken, true, true, 5, true, true);
+ assertNotSame(item, emptyItem);
+ assertNotEquals(item, emptyItem);
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ PauseActivityItem item2 = PauseActivityItem.obtain(
+ mActivityToken, true, false, 5, true, true);
+ assertSame(item, item2);
+ assertNotEquals(item2, emptyItem);
+ }
+
+ @Test
+ public void testRecycleResumeActivityItem() {
+ ResumeActivityItem emptyItem = ResumeActivityItem.obtain(
+ null /* activityToken */, false, false);
+ ResumeActivityItem item = ResumeActivityItem.obtain(mActivityToken, 3, true, false);
+ assertNotSame(item, emptyItem);
+ assertNotEquals(item, emptyItem);
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ ResumeActivityItem item2 = ResumeActivityItem.obtain(mActivityToken, 2, true, false);
+ assertSame(item, item2);
+ assertNotEquals(item2, emptyItem);
+ }
+
+ @Test
+ public void testRecycleStartActivityItem() {
+ StartActivityItem emptyItem = StartActivityItem.obtain(
+ null /* activityToken */, null /* activityOptions */);
+ StartActivityItem item = StartActivityItem.obtain(mActivityToken,
+ ActivityOptions.makeBasic());
+ assertNotSame(item, emptyItem);
+ assertNotEquals(item, emptyItem);
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ StartActivityItem item2 = StartActivityItem.obtain(mActivityToken,
ActivityOptions.makeBasic().setLaunchDisplayId(10));
assertSame(item, item2);
assertNotEquals(item2, emptyItem);
@@ -268,17 +294,17 @@
@Test
public void testRecycleStopItem() {
- StopActivityItem emptyItem = StopActivityItem.obtain(0);
- StopActivityItem item = StopActivityItem.obtain(4);
+ StopActivityItem emptyItem = StopActivityItem.obtain(null /* activityToken */, 0);
+ StopActivityItem item = StopActivityItem.obtain(mActivityToken, 4);
assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
+ assertNotEquals(item, emptyItem);
item.recycle();
assertEquals(item, emptyItem);
- StopActivityItem item2 = StopActivityItem.obtain(3);
+ StopActivityItem item2 = StopActivityItem.obtain(mActivityToken, 3);
assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
+ assertNotEquals(item2, emptyItem);
}
@Test
@@ -286,13 +312,13 @@
ClientTransaction emptyItem = ClientTransaction.obtain(null, null);
ClientTransaction item = ClientTransaction.obtain(null, new Binder());
assertNotSame(item, emptyItem);
- assertFalse(item.equals(emptyItem));
+ assertNotEquals(item, emptyItem);
item.recycle();
assertEquals(item, emptyItem);
ClientTransaction item2 = ClientTransaction.obtain(null, new Binder());
assertSame(item, item2);
- assertFalse(item2.equals(emptyItem));
+ assertNotEquals(item2, emptyItem);
}
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index 0ed6a29..5a88bad 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -18,6 +18,8 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
@@ -90,129 +92,175 @@
}
static class LaunchActivityItemBuilder {
+ @Nullable
+ private IBinder mActivityToken;
+ @Nullable
private Intent mIntent;
private int mIdent;
+ @Nullable
private ActivityInfo mInfo;
+ @Nullable
private Configuration mCurConfig;
+ @Nullable
private Configuration mOverrideConfig;
private int mDeviceId;
+ @Nullable
private String mReferrer;
+ @Nullable
private IVoiceInteractor mVoiceInteractor;
private int mProcState;
+ @Nullable
private Bundle mState;
+ @Nullable
private PersistableBundle mPersistentState;
+ @Nullable
private List<ResultInfo> mPendingResults;
+ @Nullable
private List<ReferrerIntent> mPendingNewIntents;
+ @Nullable
private ActivityOptions mActivityOptions;
private boolean mIsForward;
+ @Nullable
private ProfilerInfo mProfilerInfo;
+ @Nullable
private IBinder mAssistToken;
+ @Nullable
private IBinder mShareableActivityToken;
private boolean mLaunchedFromBubble;
+ @Nullable
private IBinder mTaskFragmentToken;
- LaunchActivityItemBuilder setIntent(Intent intent) {
+ @NonNull
+ LaunchActivityItemBuilder setActivityToken(@Nullable IBinder activityToken) {
+ mActivityToken = activityToken;
+ return this;
+ }
+
+ @NonNull
+ LaunchActivityItemBuilder setIntent(@Nullable Intent intent) {
mIntent = intent;
return this;
}
+ @NonNull
LaunchActivityItemBuilder setIdent(int ident) {
mIdent = ident;
return this;
}
- LaunchActivityItemBuilder setInfo(ActivityInfo info) {
+ @NonNull
+ LaunchActivityItemBuilder setInfo(@Nullable ActivityInfo info) {
mInfo = info;
return this;
}
- LaunchActivityItemBuilder setCurConfig(Configuration curConfig) {
+ @NonNull
+ LaunchActivityItemBuilder setCurConfig(@Nullable Configuration curConfig) {
mCurConfig = curConfig;
return this;
}
- LaunchActivityItemBuilder setOverrideConfig(Configuration overrideConfig) {
+ @NonNull
+ LaunchActivityItemBuilder setOverrideConfig(@Nullable Configuration overrideConfig) {
mOverrideConfig = overrideConfig;
return this;
}
+ @NonNull
LaunchActivityItemBuilder setDeviceId(int deviceId) {
mDeviceId = deviceId;
return this;
}
- LaunchActivityItemBuilder setReferrer(String referrer) {
+ @NonNull
+ LaunchActivityItemBuilder setReferrer(@Nullable String referrer) {
mReferrer = referrer;
return this;
}
- LaunchActivityItemBuilder setVoiceInteractor(IVoiceInteractor voiceInteractor) {
+ @NonNull
+ LaunchActivityItemBuilder setVoiceInteractor(@Nullable IVoiceInteractor voiceInteractor) {
mVoiceInteractor = voiceInteractor;
return this;
}
+ @NonNull
LaunchActivityItemBuilder setProcState(int procState) {
mProcState = procState;
return this;
}
- LaunchActivityItemBuilder setState(Bundle state) {
+ @NonNull
+ LaunchActivityItemBuilder setState(@Nullable Bundle state) {
mState = state;
return this;
}
- LaunchActivityItemBuilder setPersistentState(PersistableBundle persistentState) {
+ @NonNull
+ LaunchActivityItemBuilder setPersistentState(@Nullable PersistableBundle persistentState) {
mPersistentState = persistentState;
return this;
}
- LaunchActivityItemBuilder setPendingResults(List<ResultInfo> pendingResults) {
+ @NonNull
+ LaunchActivityItemBuilder setPendingResults(@Nullable List<ResultInfo> pendingResults) {
mPendingResults = pendingResults;
return this;
}
- LaunchActivityItemBuilder setPendingNewIntents(List<ReferrerIntent> pendingNewIntents) {
+ @NonNull
+ LaunchActivityItemBuilder setPendingNewIntents(
+ @Nullable List<ReferrerIntent> pendingNewIntents) {
mPendingNewIntents = pendingNewIntents;
return this;
}
- LaunchActivityItemBuilder setActivityOptions(ActivityOptions activityOptions) {
+ @NonNull
+ LaunchActivityItemBuilder setActivityOptions(@Nullable ActivityOptions activityOptions) {
mActivityOptions = activityOptions;
return this;
}
+ @NonNull
LaunchActivityItemBuilder setIsForward(boolean isForward) {
mIsForward = isForward;
return this;
}
- LaunchActivityItemBuilder setProfilerInfo(ProfilerInfo profilerInfo) {
+ @NonNull
+ LaunchActivityItemBuilder setProfilerInfo(@Nullable ProfilerInfo profilerInfo) {
mProfilerInfo = profilerInfo;
return this;
}
- LaunchActivityItemBuilder setAssistToken(IBinder assistToken) {
+ @NonNull
+ LaunchActivityItemBuilder setAssistToken(@Nullable IBinder assistToken) {
mAssistToken = assistToken;
return this;
}
- LaunchActivityItemBuilder setShareableActivityToken(IBinder shareableActivityToken) {
+ @NonNull
+ LaunchActivityItemBuilder setShareableActivityToken(
+ @Nullable IBinder shareableActivityToken) {
mShareableActivityToken = shareableActivityToken;
return this;
}
+ @NonNull
LaunchActivityItemBuilder setLaunchedFromBubble(boolean launchedFromBubble) {
mLaunchedFromBubble = launchedFromBubble;
return this;
}
- LaunchActivityItemBuilder setTaskFragmentToken(IBinder taskFragmentToken) {
+ @NonNull
+ LaunchActivityItemBuilder setTaskFragmentToken(@Nullable IBinder taskFragmentToken) {
mTaskFragmentToken = taskFragmentToken;
return this;
}
+ @NonNull
LaunchActivityItem build() {
- return LaunchActivityItem.obtain(mIntent, mIdent, mInfo,
+ return LaunchActivityItem.obtain(mActivityToken, mIntent, mIdent, mInfo,
mCurConfig, mOverrideConfig, mDeviceId, mReferrer, mVoiceInteractor,
mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents,
mActivityOptions, mIsForward, mProfilerInfo, mAssistToken,
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index 32f8929..a998b26 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -227,6 +227,7 @@
when(callback2.getPostExecutionState()).thenReturn(UNDEFINED);
ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
IBinder token = mock(IBinder.class);
+ when(stateRequest.getActivityToken()).thenReturn(token);
when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class));
ClientTransaction transaction = ClientTransaction.obtain(null /* client */,
@@ -256,7 +257,7 @@
final ClientTransaction destroyTransaction = ClientTransaction.obtain(null /* client */,
token /* activityToken */);
destroyTransaction.setLifecycleStateRequest(
- DestroyActivityItem.obtain(false /* finished */, 0 /* configChanges */));
+ DestroyActivityItem.obtain(token, false /* finished */, 0 /* configChanges */));
destroyTransaction.preExecute(mTransactionHandler);
// The activity should be added to to-be-destroyed container.
assertEquals(1, mTransactionHandler.getActivitiesToBeDestroyed().size());
@@ -264,7 +265,8 @@
// A previous queued launch transaction runs on main thread (execute).
final ClientTransaction launchTransaction = ClientTransaction.obtain(null /* client */,
token /* activityToken */);
- final LaunchActivityItem launchItem = spy(new LaunchActivityItemBuilder().build());
+ final LaunchActivityItem launchItem =
+ spy(new LaunchActivityItemBuilder().setActivityToken(token).build());
launchTransaction.addCallback(launchItem);
mExecutor.execute(launchTransaction);
@@ -450,9 +452,11 @@
final ClientTransaction transaction = ClientTransaction.obtain(null /* client */, token);
final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class);
when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED);
+ when(activityItem.getActivityToken()).thenReturn(token);
transaction.addCallback(activityItem);
final ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class);
transaction.setLifecycleStateRequest(stateRequest);
+ when(stateRequest.getActivityToken()).thenReturn(token);
when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class));
mExecutor.execute(transaction);
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 48a8249..abc5d6b 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -22,7 +22,6 @@
import static android.app.servertransaction.TestUtils.resultInfoList;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import android.app.ActivityOptions;
import android.app.servertransaction.TestUtils.LaunchActivityItemBuilder;
@@ -32,6 +31,7 @@
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -61,10 +61,12 @@
public class TransactionParcelTests {
private Parcel mParcel;
+ private IBinder mActivityToken;
@Before
public void setUp() throws Exception {
mParcel = Parcel.obtain();
+ mActivityToken = new Binder();
}
@Test
@@ -77,13 +79,14 @@
ConfigurationChangeItem result = ConfigurationChangeItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
+ assertEquals(item, result);
}
@Test
public void testActivityConfigChange() {
// Write to parcel
- ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config());
+ ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(
+ mActivityToken, config());
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -91,51 +94,52 @@
ActivityConfigurationChangeItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
+ assertEquals(item, result);
}
@Test
public void testMoveToDisplay() {
// Write to parcel
- MoveToDisplayItem item = MoveToDisplayItem.obtain(4 /* targetDisplayId */, config());
+ MoveToDisplayItem item = MoveToDisplayItem.obtain(mActivityToken, 4 /* targetDisplayId */,
+ config());
writeAndPrepareForReading(item);
// Read from parcel and assert
MoveToDisplayItem result = MoveToDisplayItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
+ assertEquals(item, result);
}
@Test
public void testNewIntent() {
// Write to parcel
- NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), false);
+ NewIntentItem item = NewIntentItem.obtain(mActivityToken, referrerIntentList(), false);
writeAndPrepareForReading(item);
// Read from parcel and assert
NewIntentItem result = NewIntentItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
+ assertEquals(item, result);
}
@Test
public void testActivityResult() {
// Write to parcel
- ActivityResultItem item = ActivityResultItem.obtain(resultInfoList());
+ ActivityResultItem item = ActivityResultItem.obtain(mActivityToken, resultInfoList());
writeAndPrepareForReading(item);
// Read from parcel and assert
ActivityResultItem result = ActivityResultItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
+ assertEquals(item, result);
}
@Test
public void testDestroy() {
- DestroyActivityItem item = DestroyActivityItem.obtain(true /* finished */,
+ DestroyActivityItem item = DestroyActivityItem.obtain(mActivityToken, true /* finished */,
135 /* configChanges */);
writeAndPrepareForReading(item);
@@ -143,48 +147,59 @@
DestroyActivityItem result = DestroyActivityItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
+ assertEquals(item, result);
}
@Test
public void testLaunch() {
// Write to parcel
- Intent intent = new Intent("action");
+ final IBinder activityToken = new Binder();
+ final Intent intent = new Intent("action");
int ident = 57;
- ActivityInfo activityInfo = new ActivityInfo();
+ final ActivityInfo activityInfo = new ActivityInfo();
activityInfo.flags = 42;
activityInfo.setMaxAspectRatio(2.4f);
activityInfo.launchToken = "token";
activityInfo.applicationInfo = new ApplicationInfo();
activityInfo.packageName = "packageName";
activityInfo.name = "name";
- Configuration overrideConfig = new Configuration();
+ final Configuration overrideConfig = new Configuration();
overrideConfig.assetsSeq = 5;
- String referrer = "referrer";
+ final String referrer = "referrer";
int procState = 4;
- Bundle bundle = new Bundle();
+ final Bundle bundle = new Bundle();
bundle.putString("key", "value");
bundle.putParcelable("data", new ParcelableData(1));
- PersistableBundle persistableBundle = new PersistableBundle();
+ final PersistableBundle persistableBundle = new PersistableBundle();
persistableBundle.putInt("k", 4);
- LaunchActivityItem item = new LaunchActivityItemBuilder()
- .setIntent(intent).setIdent(ident).setInfo(activityInfo).setCurConfig(config())
- .setOverrideConfig(overrideConfig).setReferrer(referrer)
- .setProcState(procState).setState(bundle).setPersistentState(persistableBundle)
- .setPendingResults(resultInfoList()).setActivityOptions(ActivityOptions.makeBasic())
- .setPendingNewIntents(referrerIntentList()).setIsForward(true)
- .setAssistToken(new Binder()).setShareableActivityToken(new Binder())
+ final LaunchActivityItem item = new LaunchActivityItemBuilder()
+ .setActivityToken(activityToken)
+ .setIntent(intent)
+ .setIdent(ident)
+ .setInfo(activityInfo)
+ .setCurConfig(config())
+ .setOverrideConfig(overrideConfig)
+ .setReferrer(referrer)
+ .setProcState(procState)
+ .setState(bundle)
+ .setPersistentState(persistableBundle)
+ .setPendingResults(resultInfoList())
+ .setActivityOptions(ActivityOptions.makeBasic())
+ .setPendingNewIntents(referrerIntentList())
+ .setIsForward(true)
+ .setAssistToken(new Binder())
+ .setShareableActivityToken(new Binder())
.setTaskFragmentToken(new Binder())
.build();
writeAndPrepareForReading(item);
// Read from parcel and assert
- LaunchActivityItem result = LaunchActivityItem.CREATOR.createFromParcel(mParcel);
+ final LaunchActivityItem result = LaunchActivityItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
+ assertEquals(item, result);
}
@Test
@@ -192,7 +207,7 @@
// Write to parcel
Configuration overrideConfig = new Configuration();
overrideConfig.assetsSeq = 5;
- ActivityRelaunchItem item = ActivityRelaunchItem.obtain(resultInfoList(),
+ ActivityRelaunchItem item = ActivityRelaunchItem.obtain(mActivityToken, resultInfoList(),
referrerIntentList(), 35, mergedConfig(), true);
writeAndPrepareForReading(item);
@@ -200,13 +215,13 @@
ActivityRelaunchItem result = ActivityRelaunchItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
+ assertEquals(item, result);
}
@Test
public void testPause() {
// Write to parcel
- PauseActivityItem item = PauseActivityItem.obtain(true /* finished */,
+ PauseActivityItem item = PauseActivityItem.obtain(mActivityToken, true /* finished */,
true /* userLeaving */, 135 /* configChanges */, true /* dontReport */,
true /* autoEnteringPip */);
writeAndPrepareForReading(item);
@@ -215,13 +230,13 @@
PauseActivityItem result = PauseActivityItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
+ assertEquals(item, result);
}
@Test
public void testResume() {
// Write to parcel
- ResumeActivityItem item = ResumeActivityItem.obtain(27 /* procState */,
+ ResumeActivityItem item = ResumeActivityItem.obtain(mActivityToken, 27 /* procState */,
true /* isForward */, false /* shouldSendCompatFakeFocus */);
writeAndPrepareForReading(item);
@@ -229,26 +244,27 @@
ResumeActivityItem result = ResumeActivityItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
+ assertEquals(item, result);
}
@Test
public void testStop() {
// Write to parcel
- StopActivityItem item = StopActivityItem.obtain(14 /* configChanges */);
+ StopActivityItem item = StopActivityItem.obtain(mActivityToken, 14 /* configChanges */);
writeAndPrepareForReading(item);
// Read from parcel and assert
StopActivityItem result = StopActivityItem.CREATOR.createFromParcel(mParcel);
assertEquals(item.hashCode(), result.hashCode());
- assertTrue(item.equals(result));
+ assertEquals(item, result);
}
@Test
public void testStart() {
// Write to parcel
- StartActivityItem item = StartActivityItem.obtain(ActivityOptions.makeBasic());
+ StartActivityItem item = StartActivityItem.obtain(mActivityToken,
+ ActivityOptions.makeBasic());
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -261,11 +277,12 @@
@Test
public void testClientTransaction() {
// Write to parcel
- NewIntentItem callback1 = NewIntentItem.obtain(new ArrayList<>(), true);
+ NewIntentItem callback1 = NewIntentItem.obtain(mActivityToken, new ArrayList<>(), true);
ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
- config());
+ mActivityToken, config());
- StopActivityItem lifecycleRequest = StopActivityItem.obtain(78 /* configChanges */);
+ StopActivityItem lifecycleRequest = StopActivityItem.obtain(mActivityToken,
+ 78 /* configChanges */);
Binder activityToken = new Binder();
@@ -280,15 +297,15 @@
ClientTransaction result = ClientTransaction.CREATOR.createFromParcel(mParcel);
assertEquals(transaction.hashCode(), result.hashCode());
- assertTrue(transaction.equals(result));
+ assertEquals(transaction, result);
}
@Test
public void testClientTransactionCallbacksOnly() {
// Write to parcel
- NewIntentItem callback1 = NewIntentItem.obtain(new ArrayList<>(), true);
+ NewIntentItem callback1 = NewIntentItem.obtain(mActivityToken, new ArrayList<>(), true);
ActivityConfigurationChangeItem callback2 = ActivityConfigurationChangeItem.obtain(
- config());
+ mActivityToken, config());
Binder activityToken = new Binder();
@@ -302,13 +319,14 @@
ClientTransaction result = ClientTransaction.CREATOR.createFromParcel(mParcel);
assertEquals(transaction.hashCode(), result.hashCode());
- assertTrue(transaction.equals(result));
+ assertEquals(transaction, result);
}
@Test
public void testClientTransactionLifecycleOnly() {
// Write to parcel
- StopActivityItem lifecycleRequest = StopActivityItem.obtain(78 /* configChanges */);
+ StopActivityItem lifecycleRequest = StopActivityItem.obtain(mActivityToken,
+ 78 /* configChanges */);
Binder activityToken = new Binder();
@@ -321,7 +339,7 @@
ClientTransaction result = ClientTransaction.CREATOR.createFromParcel(mParcel);
assertEquals(transaction.hashCode(), result.hashCode());
- assertTrue(transaction.equals(result));
+ assertEquals(transaction, result);
}
/** Write to {@link #mParcel} and reset its position to prepare for reading from the start. */
diff --git a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
index be156c8..13ce253 100644
--- a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
@@ -17,6 +17,15 @@
package android.database;
import static android.database.DatabaseUtils.bindSelection;
+import static android.database.DatabaseUtils.getSqlStatementType;
+import static android.database.DatabaseUtils.getSqlStatementTypeExtended;
+import static android.database.DatabaseUtils.STATEMENT_COMMENT;
+import static android.database.DatabaseUtils.STATEMENT_CREATE;
+import static android.database.DatabaseUtils.STATEMENT_DDL;
+import static android.database.DatabaseUtils.STATEMENT_OTHER;
+import static android.database.DatabaseUtils.STATEMENT_SELECT;
+import static android.database.DatabaseUtils.STATEMENT_UPDATE;
+import static android.database.DatabaseUtils.STATEMENT_WITH;
import static org.junit.Assert.assertEquals;
@@ -63,4 +72,39 @@
bindSelection("foo=?10 AND bar=? AND meow=?1",
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12));
}
+
+ @Test
+ public void testStatementType() {
+ final int sel = STATEMENT_SELECT;
+ assertEquals(sel, getSqlStatementType("SELECT"));
+ assertEquals(sel, getSqlStatementType(" SELECT"));
+ assertEquals(sel, getSqlStatementType(" \n SELECT"));
+
+ final int upd = STATEMENT_UPDATE;
+ assertEquals(upd, getSqlStatementType("UPDATE"));
+ assertEquals(upd, getSqlStatementType(" UPDATE"));
+ assertEquals(upd, getSqlStatementType(" \n UPDATE"));
+
+ final int ddl = STATEMENT_DDL;
+ assertEquals(ddl, getSqlStatementType("ALTER TABLE t1 ADD COLUMN j int"));
+ assertEquals(ddl, getSqlStatementType("CREATE TABLE t1 (i int)"));
+
+ // Short statements, leading comments, and WITH are decoded to "other" in the public API.
+ final int othr = STATEMENT_OTHER;
+ assertEquals(othr, getSqlStatementType("SE"));
+ assertEquals(othr, getSqlStatementType("SE LECT"));
+ assertEquals(othr, getSqlStatementType("-- cmt\n SE"));
+ assertEquals(othr, getSqlStatementType("WITH"));
+
+ // Test the extended statement types.
+
+ final int wit = STATEMENT_WITH;
+ assertEquals(wit, getSqlStatementTypeExtended("WITH"));
+
+ final int cmt = STATEMENT_COMMENT;
+ assertEquals(cmt, getSqlStatementTypeExtended("-- cmt\n SELECT"));
+
+ final int cre = STATEMENT_CREATE;
+ assertEquals(cre, getSqlStatementTypeExtended("CREATE TABLE t1 (i int)"));
+ }
}
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 349fe7b..9840e15 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -20,6 +20,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.testng.Assert.assertThrows;
import android.app.ActivityThread;
@@ -28,6 +29,7 @@
import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -625,6 +627,7 @@
}
@Test
+ @FlakyTest(bugId = 299483542)
public void setProperties_multipleNamespaces() throws DeviceConfig.BadConfigException {
final String namespace2 = "namespace2";
Properties properties1 = new Properties.Builder(NAMESPACE).setString(KEY, VALUE)
@@ -632,8 +635,8 @@
Properties properties2 = new Properties.Builder(namespace2).setString(KEY2, VALUE)
.setString(KEY3, VALUE2).build();
- DeviceConfig.setProperties(properties1);
- DeviceConfig.setProperties(properties2);
+ assertTrue(DeviceConfig.setProperties(properties1));
+ assertTrue(DeviceConfig.setProperties(properties2));
Properties properties = DeviceConfig.getProperties(NAMESPACE);
assertThat(properties.getKeyset()).containsExactly(KEY, KEY2);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index e03e1ec..ccf9552 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -319,17 +319,13 @@
return features;
}
- // We will transform the feature bounds to the Activity window, so using the rotation
- // from the same source (WindowConfiguration) to make sure they are synchronized.
- final int rotation = windowConfiguration.getDisplayRotation();
-
for (CommonFoldingFeature baseFeature : storedFeatures) {
Integer state = convertToExtensionState(baseFeature.getState());
if (state == null) {
continue;
}
Rect featureRect = baseFeature.getRect();
- rotateRectToDisplayRotation(displayId, rotation, featureRect);
+ rotateRectToDisplayRotation(displayId, featureRect);
transformToWindowSpaceRect(windowConfiguration, featureRect);
if (isZero(featureRect)) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
index 15a329bd..5bfb0ebd 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
@@ -120,12 +120,10 @@
}
List<SidecarDisplayFeature> features = new ArrayList<>();
- final int rotation = activity.getResources().getConfiguration().windowConfiguration
- .getDisplayRotation();
for (CommonFoldingFeature baseFeature : mStoredFeatures) {
SidecarDisplayFeature feature = new SidecarDisplayFeature();
Rect featureRect = baseFeature.getRect();
- rotateRectToDisplayRotation(displayId, rotation, featureRect);
+ rotateRectToDisplayRotation(displayId, featureRect);
transformToWindowSpaceRect(activity, featureRect);
feature.setRect(featureRect);
feature.setType(baseFeature.getType());
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
index 6b193fc..9e2611f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
@@ -16,6 +16,8 @@
package androidx.window.util;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
@@ -23,14 +25,12 @@
import android.content.Context;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
-import android.util.RotationUtils;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.UiContext;
-import androidx.annotation.VisibleForTesting;
/**
* Util class for both Sidecar and Extensions.
@@ -44,41 +44,47 @@
/**
* Rotates the input rectangle specified in default display orientation to the current display
* rotation.
- *
- * @param displayId the display id.
- * @param rotation the target rotation relative to the default display orientation.
- * @param inOutRect the input/output Rect as specified in the default display orientation.
*/
- public static void rotateRectToDisplayRotation(
- int displayId, @Surface.Rotation int rotation, @NonNull Rect inOutRect) {
- final DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance();
- final DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId);
+ public static void rotateRectToDisplayRotation(int displayId, Rect inOutRect) {
+ DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance();
+ DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId);
+ int rotation = displayInfo.rotation;
- rotateRectToDisplayRotation(displayInfo, rotation, inOutRect);
+ boolean isSideRotation = rotation == ROTATION_90 || rotation == ROTATION_270;
+ int displayWidth = isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
+ int displayHeight = isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight;
+
+ inOutRect.intersect(0, 0, displayWidth, displayHeight);
+
+ rotateBounds(inOutRect, displayWidth, displayHeight, rotation);
}
- @VisibleForTesting
- static void rotateRectToDisplayRotation(@NonNull DisplayInfo displayInfo,
- @Surface.Rotation int rotation, @NonNull Rect inOutRect) {
- // The inOutRect is specified in the default display orientation, so here we need to get
- // the display width and height in the default orientation to perform the intersection and
- // rotation.
- final boolean isSideRotation =
- displayInfo.rotation == ROTATION_90 || displayInfo.rotation == ROTATION_270;
- final int baseDisplayWidth =
- isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
- final int baseDisplayHeight =
- isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight;
-
- final boolean success = inOutRect.intersect(0, 0, baseDisplayWidth, baseDisplayHeight);
- if (!success) {
- throw new IllegalArgumentException("inOutRect must intersect with the display."
- + " inOutRect: " + inOutRect
- + ", baseDisplayWidth: " + baseDisplayWidth
- + ", baseDisplayHeight: " + baseDisplayHeight);
+ /**
+ * Rotates the input rectangle within parent bounds for a given delta.
+ */
+ private static void rotateBounds(Rect inOutRect, int parentWidth, int parentHeight,
+ @Surface.Rotation int delta) {
+ int origLeft = inOutRect.left;
+ switch (delta) {
+ case ROTATION_0:
+ return;
+ case ROTATION_90:
+ inOutRect.left = inOutRect.top;
+ inOutRect.top = parentWidth - inOutRect.right;
+ inOutRect.right = inOutRect.bottom;
+ inOutRect.bottom = parentWidth - origLeft;
+ return;
+ case ROTATION_180:
+ inOutRect.left = parentWidth - inOutRect.right;
+ inOutRect.right = parentWidth - origLeft;
+ return;
+ case ROTATION_270:
+ inOutRect.left = parentHeight - inOutRect.bottom;
+ inOutRect.bottom = inOutRect.right;
+ inOutRect.right = parentHeight - inOutRect.top;
+ inOutRect.top = origLeft;
+ return;
}
-
- RotationUtils.rotateBounds(inOutRect, baseDisplayWidth, baseDisplayHeight, rotation);
}
/** Transforms rectangle from absolute coordinate space to the window coordinate space. */
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
index 0682692..45564cb 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
@@ -32,7 +32,7 @@
import org.junit.runner.RunWith;
/**
- * Test class for {@link WindowExtensions}.
+ * Test class for {@link WindowExtensionsTest}.
*
* Build/Install/Run:
* atest WMJetpackUnitTests:WindowExtensionsTest
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/util/ExtensionHelperTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/util/ExtensionHelperTest.java
deleted file mode 100644
index ae783de..0000000
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/util/ExtensionHelperTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.window.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThrows;
-
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-import android.view.DisplayInfo;
-import android.view.Surface;
-
-import androidx.annotation.NonNull;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test class for {@link ExtensionHelper}.
- *
- * Build/Install/Run:
- * atest WMJetpackUnitTests:ExtensionHelperTest
- */
-@Presubmit
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class ExtensionHelperTest {
-
- private static final int MOCK_DISPLAY_HEIGHT = 1000;
- private static final int MOCK_DISPLAY_WIDTH = 2000;
- private static final int MOCK_FEATURE_LEFT = 100;
- private static final int MOCK_FEATURE_RIGHT = 200;
-
- private static final int[] ROTATIONS = {
- Surface.ROTATION_0,
- Surface.ROTATION_90,
- Surface.ROTATION_180,
- Surface.ROTATION_270
- };
-
- private static final DisplayInfo[] MOCK_DISPLAY_INFOS = {
- getMockDisplayInfo(Surface.ROTATION_0),
- getMockDisplayInfo(Surface.ROTATION_90),
- getMockDisplayInfo(Surface.ROTATION_180),
- getMockDisplayInfo(Surface.ROTATION_270),
- };
-
- @Test
- public void testRotateRectToDisplayRotation() {
- for (int rotation : ROTATIONS) {
- final Rect expectedResult = getExpectedFeatureRectAfterRotation(rotation);
- // The method should return correctly rotated Rect even if the requested rotation value
- // differs from the rotation in DisplayInfo. This is because the WindowConfiguration is
- // not always synced with DisplayInfo.
- for (DisplayInfo displayInfo : MOCK_DISPLAY_INFOS) {
- final Rect rect = getMockFeatureRect();
- ExtensionHelper.rotateRectToDisplayRotation(displayInfo, rotation, rect);
- assertEquals(
- "Result Rect should equal to expected for rotation: " + rotation
- + "; displayInfo: " + displayInfo,
- expectedResult, rect);
- }
- }
- }
-
- @Test
- public void testRotateRectToDisplayRotation_invalidInputRect() {
- final Rect invalidRect = new Rect(
- MOCK_DISPLAY_WIDTH + 10, 0, MOCK_DISPLAY_WIDTH + 10, MOCK_DISPLAY_HEIGHT);
- assertThrows(IllegalArgumentException.class,
- () -> ExtensionHelper.rotateRectToDisplayRotation(
- MOCK_DISPLAY_INFOS[0], ROTATIONS[0], invalidRect));
- }
-
-
- @NonNull
- private static DisplayInfo getMockDisplayInfo(@Surface.Rotation int rotation) {
- final DisplayInfo displayInfo = new DisplayInfo();
- displayInfo.rotation = rotation;
- if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
- displayInfo.logicalWidth = MOCK_DISPLAY_WIDTH;
- displayInfo.logicalHeight = MOCK_DISPLAY_HEIGHT;
- } else {
- displayInfo.logicalWidth = MOCK_DISPLAY_HEIGHT;
- displayInfo.logicalHeight = MOCK_DISPLAY_WIDTH;
- }
- return displayInfo;
- }
-
- @NonNull
- private static Rect getMockFeatureRect() {
- return new Rect(MOCK_FEATURE_LEFT, 0, MOCK_FEATURE_RIGHT, MOCK_DISPLAY_HEIGHT);
- }
-
- @NonNull
- private static Rect getExpectedFeatureRectAfterRotation(@Surface.Rotation int rotation) {
- switch (rotation) {
- case Surface.ROTATION_0:
- return new Rect(
- MOCK_FEATURE_LEFT, 0, MOCK_FEATURE_RIGHT, MOCK_DISPLAY_HEIGHT);
- case Surface.ROTATION_90:
- return new Rect(0, MOCK_DISPLAY_WIDTH - MOCK_FEATURE_RIGHT,
- MOCK_DISPLAY_HEIGHT, MOCK_DISPLAY_WIDTH - MOCK_FEATURE_LEFT);
- case Surface.ROTATION_180:
- return new Rect(MOCK_DISPLAY_WIDTH - MOCK_FEATURE_RIGHT, 0,
- MOCK_DISPLAY_WIDTH - MOCK_FEATURE_LEFT, MOCK_DISPLAY_HEIGHT);
- case Surface.ROTATION_270:
- return new Rect(0, MOCK_FEATURE_LEFT, MOCK_DISPLAY_HEIGHT,
- MOCK_FEATURE_RIGHT);
- default:
- throw new IllegalArgumentException("Unknown rotation value: " + rotation);
- }
- }
-}
diff --git a/libs/WindowManager/Shell/res/values-television/config.xml b/libs/WindowManager/Shell/res/values-television/config.xml
index cc0333e..5f9dbdb 100644
--- a/libs/WindowManager/Shell/res/values-television/config.xml
+++ b/libs/WindowManager/Shell/res/values-television/config.xml
@@ -44,12 +44,11 @@
if a custom action is present before closing it. -->
<integer name="config_pipForceCloseDelay">5000</integer>
- <!-- Animation duration when exit starting window: fade out icon -->
- <integer name="starting_window_app_reveal_icon_fade_out_duration">0</integer>
-
<!-- Animation duration when exit starting window: reveal app -->
- <integer name="starting_window_app_reveal_anim_delay">0</integer>
+ <integer name="starting_window_app_reveal_anim_duration">500</integer>
- <!-- Animation duration when exit starting window: reveal app -->
- <integer name="starting_window_app_reveal_anim_duration">0</integer>
+ <!-- Default animation type when hiding the starting window. The possible values are:
+ - 0 for radial vanish + slide up
+ - 1 for fade out -->
+ <integer name="starting_window_exit_animation_type">1</integer>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index a3916b7..97a9d48 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -83,6 +83,11 @@
<!-- Animation duration when exit starting window: reveal app -->
<integer name="starting_window_app_reveal_anim_duration">266</integer>
+ <!-- Default animation type when hiding the starting window. The possible values are:
+ - 0 for radial vanish + slide up
+ - 1 for fade out -->
+ <integer name="starting_window_exit_animation_type">0</integer>
+
<!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
These values are in DPs and will be converted to pixel sizes internally. -->
<string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index d10de83..3f9dcc1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -25,6 +25,7 @@
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
+import static com.android.wm.shell.common.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
import android.animation.Animator;
@@ -131,9 +132,6 @@
private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150;
- /** Should be kept in sync with value in TaskbarScrimViewController. */
- private static final float SCRIM_ALPHA = 0.32f;
-
/** Minimum alpha value for scrim when alpha is being changed via drag */
private static final float MIN_SCRIM_ALPHA_FOR_DRAG = 0.2f;
@@ -780,14 +778,15 @@
private float getScrimAlphaForDrag(float dragAmount) {
// dragAmount should be negative as we allow scroll up only
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
- float alphaRange = SCRIM_ALPHA - MIN_SCRIM_ALPHA_FOR_DRAG;
+ float alphaRange = BUBBLE_EXPANDED_SCRIM_ALPHA - MIN_SCRIM_ALPHA_FOR_DRAG;
int dragMax = mExpandedBubble.getExpandedView().getContentHeight();
float dragFraction = dragAmount / dragMax;
- return Math.max(SCRIM_ALPHA - alphaRange * dragFraction, MIN_SCRIM_ALPHA_FOR_DRAG);
+ return Math.max(BUBBLE_EXPANDED_SCRIM_ALPHA - alphaRange * dragFraction,
+ MIN_SCRIM_ALPHA_FOR_DRAG);
}
- return SCRIM_ALPHA;
+ return BUBBLE_EXPANDED_SCRIM_ALPHA;
}
};
@@ -2215,7 +2214,7 @@
if (show) {
mScrim.animate()
.setInterpolator(ALPHA_IN)
- .alpha(SCRIM_ALPHA)
+ .alpha(BUBBLE_EXPANDED_SCRIM_ALPHA)
.setListener(listener)
.start();
} else {
@@ -2944,7 +2943,7 @@
mBubbleController.getSysuiProxy().onManageMenuExpandChanged(show);
mManageMenuScrim.animate()
.setInterpolator(show ? ALPHA_IN : ALPHA_OUT)
- .alpha(show ? SCRIM_ALPHA : 0f)
+ .alpha(show ? BUBBLE_EXPANDED_SCRIM_ALPHA : 0f)
.withEndAction(endAction)
.start();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleConstants.java
new file mode 100644
index 0000000..0329b8d
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleConstants.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common.bubbles;
+
+/**
+ * Constants shared between bubbles in shell & things we have to do for bubbles in launcher.
+ */
+public class BubbleConstants {
+
+ /** The alpha for the scrim shown when bubbles are expanded. */
+ public static float BUBBLE_EXPANDED_SCRIM_ALPHA = .32f;
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index c05af73..c0fc02fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -52,8 +52,8 @@
private val activeTasksListeners = ArraySet<ActiveTasksListener>()
// Track visible tasks separately because a task may be part of the desktop but not visible.
private val visibleTasksListeners = ArrayMap<VisibleTasksListener, Executor>()
- // Track corners of desktop tasks, used to determine gesture exclusion
- private val desktopCorners = SparseArray<Region>()
+ // Track corner/caption regions of desktop tasks, used to determine gesture exclusion
+ private val desktopExclusionRegions = SparseArray<Region>()
private var desktopGestureExclusionListener: Consumer<Region>? = null
private var desktopGestureExclusionExecutor: Executor? = null
@@ -96,10 +96,11 @@
}
/**
- * Add a Consumer which will inform other classes of changes to corners for all Desktop tasks.
+ * Add a Consumer which will inform other classes of changes to exclusion regions for all
+ * Desktop tasks.
*/
- fun setTaskCornerListener(cornersListener: Consumer<Region>, executor: Executor) {
- desktopGestureExclusionListener = cornersListener
+ fun setExclusionRegionListener(regionListener: Consumer<Region>, executor: Executor) {
+ desktopGestureExclusionListener = regionListener
desktopGestureExclusionExecutor = executor
executor.execute {
desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion())
@@ -107,14 +108,14 @@
}
/**
- * Create a new merged region representative of all corners in all desktop tasks.
+ * Create a new merged region representative of all exclusion regions in all desktop tasks.
*/
private fun calculateDesktopExclusionRegion(): Region {
- val desktopCornersRegion = Region()
- desktopCorners.valueIterator().forEach { taskCorners ->
- desktopCornersRegion.op(taskCorners, Region.Op.UNION)
+ val desktopExclusionRegion = Region()
+ desktopExclusionRegions.valueIterator().forEach { taskExclusionRegion ->
+ desktopExclusionRegion.op(taskExclusionRegion, Region.Op.UNION)
}
- return desktopCornersRegion
+ return desktopExclusionRegion
}
/**
@@ -294,22 +295,24 @@
}
/**
- * Updates the active desktop corners; if desktopCorners has been accepted by
- * desktopCornersListener, it will be updated in the appropriate classes.
+ * Updates the active desktop gesture exclusion regions; if desktopExclusionRegions has been
+ * accepted by desktopGestureExclusionListener, it will be updated in the
+ * appropriate classes.
*/
- fun updateTaskCorners(taskId: Int, taskCorners: Region) {
- desktopCorners.put(taskId, taskCorners)
+ fun updateTaskExclusionRegions(taskId: Int, taskExclusionRegions: Region) {
+ desktopExclusionRegions.put(taskId, taskExclusionRegions)
desktopGestureExclusionExecutor?.execute {
desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion())
}
}
/**
- * Removes the active desktop corners for the specified task; if desktopCorners has been
- * accepted by desktopCornersListener, it will be updated in the appropriate classes.
+ * Removes the desktop gesture exclusion region for the specified task; if exclusionRegion
+ * has been accepted by desktopGestureExclusionListener, it will be updated in the
+ * appropriate classes.
*/
- fun removeTaskCorners(taskId: Int) {
- desktopCorners.delete(taskId)
+ fun removeExclusionRegion(taskId: Int) {
+ desktopExclusionRegions.delete(taskId)
desktopGestureExclusionExecutor?.execute {
desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion())
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 40c519e..9ce0118 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -968,17 +968,17 @@
}
/**
- * Update the corner region for a specified task
+ * Update the exclusion region for a specified task
*/
- fun onTaskCornersChanged(taskId: Int, corner: Region) {
- desktopModeTaskRepository.updateTaskCorners(taskId, corner)
+ fun onExclusionRegionChanged(taskId: Int, exclusionRegion: Region) {
+ desktopModeTaskRepository.updateTaskExclusionRegions(taskId, exclusionRegion)
}
/**
- * Remove a previously tracked corner region for a specified task.
+ * Remove a previously tracked exclusion region for a specified task.
*/
- fun removeCornersForTask(taskId: Int) {
- desktopModeTaskRepository.removeTaskCorners(taskId)
+ fun removeExclusionRegionForTask(taskId: Int) {
+ desktopModeTaskRepository.removeExclusionRegion(taskId)
}
/**
@@ -992,16 +992,16 @@
}
/**
- * Adds a listener to track changes to desktop task corners
+ * Adds a listener to track changes to desktop task gesture exclusion regions
*
* @param listener the listener to add.
* @param callbackExecutor the executor to call the listener on.
*/
- fun setTaskCornerListener(
+ fun setTaskRegionListener(
listener: Consumer<Region>,
callbackExecutor: Executor
) {
- desktopModeTaskRepository.setTaskCornerListener(listener, callbackExecutor)
+ desktopModeTaskRepository.setExclusionRegionListener(listener, callbackExecutor)
}
private fun dump(pw: PrintWriter, prefix: String) {
@@ -1027,7 +1027,7 @@
callbackExecutor: Executor
) {
mainExecutor.execute {
- this@DesktopTasksController.setTaskCornerListener(listener, callbackExecutor)
+ this@DesktopTasksController.setTaskRegionListener(listener, callbackExecutor)
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
index 20da877..cb76044 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
@@ -20,6 +20,7 @@
import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLASHSCREEN_EXIT_ANIM;
import android.animation.Animator;
+import android.annotation.IntDef;
import android.content.Context;
import android.graphics.Rect;
import android.util.Slog;
@@ -46,6 +47,8 @@
private final int mIconFadeOutDuration;
private final int mAppRevealDelay;
private final int mAppRevealDuration;
+ @ExitAnimationType
+ private final int mAnimationType;
private final int mAnimationDuration;
private final float mIconStartAlpha;
private final float mBrandingStartAlpha;
@@ -55,6 +58,24 @@
private Runnable mFinishCallback;
+ /**
+ * This splash screen exit animation type uses a radial vanish to hide
+ * the starting window and slides up the main window content.
+ */
+ private static final int TYPE_RADIAL_VANISH_SLIDE_UP = 0;
+
+ /**
+ * This splash screen exit animation type fades out the starting window
+ * to reveal the main window content.
+ */
+ private static final int TYPE_FADE_OUT = 1;
+
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_RADIAL_VANISH_SLIDE_UP,
+ TYPE_FADE_OUT,
+ })
+ private @interface ExitAnimationType {}
+
SplashScreenExitAnimation(Context context, SplashScreenView view, SurfaceControl leash,
Rect frame, int mainWindowShiftLength, TransactionPool pool, Runnable handleFinish,
float roundedCornerRadius) {
@@ -91,6 +112,8 @@
}
mAppRevealDuration = context.getResources().getInteger(
R.integer.starting_window_app_reveal_anim_duration);
+ mAnimationType = context.getResources().getInteger(
+ R.integer.starting_window_exit_animation_type);
mAnimationDuration = Math.max(mIconFadeOutDuration, mAppRevealDelay + mAppRevealDuration);
mMainWindowShiftLength = mainWindowShiftLength;
mFinishCallback = handleFinish;
@@ -98,10 +121,15 @@
}
void startAnimations() {
- SplashScreenExitAnimationUtils.startAnimations(mSplashScreenView, mFirstWindowSurface,
- mMainWindowShiftLength, mTransactionPool, mFirstWindowFrame, mAnimationDuration,
- mIconFadeOutDuration, mIconStartAlpha, mBrandingStartAlpha, mAppRevealDelay,
- mAppRevealDuration, this, mRoundedCornerRadius);
+ if (mAnimationType == TYPE_FADE_OUT) {
+ SplashScreenExitAnimationUtils.startFadeOutAnimation(mSplashScreenView,
+ mAnimationDuration, this);
+ } else {
+ SplashScreenExitAnimationUtils.startAnimations(mSplashScreenView, mFirstWindowSurface,
+ mMainWindowShiftLength, mTransactionPool, mFirstWindowFrame, mAnimationDuration,
+ mIconFadeOutDuration, mIconStartAlpha, mBrandingStartAlpha, mAppRevealDelay,
+ mAppRevealDuration, this, mRoundedCornerRadius);
+ }
}
private void reset() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java
index a7e4385..64f09a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java
@@ -71,11 +71,10 @@
int iconFadeOutDuration, float iconStartAlpha, float brandingStartAlpha,
int appRevealDelay, int appRevealDuration, Animator.AnimatorListener animatorListener,
float roundedCornerRadius) {
- ValueAnimator animator =
- createAnimator(splashScreenView, firstWindowSurface, mainWindowShiftLength,
- transactionPool, firstWindowFrame, animationDuration, iconFadeOutDuration,
- iconStartAlpha, brandingStartAlpha, appRevealDelay, appRevealDuration,
- animatorListener, roundedCornerRadius);
+ ValueAnimator animator = createRadialVanishSlideUpAnimator(splashScreenView,
+ firstWindowSurface, mainWindowShiftLength, transactionPool, firstWindowFrame,
+ animationDuration, iconFadeOutDuration, iconStartAlpha, brandingStartAlpha,
+ appRevealDelay, appRevealDuration, animatorListener, roundedCornerRadius);
animator.start();
}
@@ -99,7 +98,7 @@
* Creates the animator to fade out the icon, reveal the app, and shift up main window.
* @hide
*/
- private static ValueAnimator createAnimator(ViewGroup splashScreenView,
+ private static ValueAnimator createRadialVanishSlideUpAnimator(ViewGroup splashScreenView,
SurfaceControl firstWindowSurface, int mMainWindowShiftLength,
TransactionPool transactionPool, Rect firstWindowFrame, int animationDuration,
int iconFadeOutDuration, float iconStartAlpha, float brandingStartAlpha,
@@ -210,6 +209,20 @@
return nightMode == Configuration.UI_MODE_NIGHT_YES;
}
+ static void startFadeOutAnimation(ViewGroup splashScreenView,
+ int animationDuration, Animator.AnimatorListener animatorListener) {
+ final ValueAnimator animator = ValueAnimator.ofFloat(1f, 0f);
+ animator.setDuration(animationDuration);
+ animator.setInterpolator(Interpolators.LINEAR);
+ animator.addUpdateListener(animation -> {
+ splashScreenView.setAlpha((float) animation.getAnimatedValue());
+ });
+ if (animatorListener != null) {
+ animator.addListener(animatorListener);
+ }
+ animator.start();
+ }
+
/**
* View which creates a circular reveal of the underlying view.
* @hide
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index abd2ad4..026d0cd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -21,7 +21,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
@@ -79,7 +78,7 @@
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
-import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.TaskCornersListener;
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionRegionListener;
import java.util.Optional;
import java.util.function.Supplier;
@@ -106,7 +105,8 @@
private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>();
- private final TaskCornersListener mCornersListener = new TaskCornersListenerImpl();
+ private final ExclusionRegionListener mExclusionRegionListener =
+ new ExclusionRegionListenerImpl();
private final SparseArray<DesktopModeWindowDecoration> mWindowDecorByTaskId =
new SparseArray<>();
@@ -920,7 +920,7 @@
windowDecoration.setCaptionListeners(
touchEventListener, touchEventListener, touchEventListener);
- windowDecoration.setCornersListener(mCornersListener);
+ windowDecoration.setExclusionRegionListener(mExclusionRegionListener);
windowDecoration.setDragPositioningCallback(dragPositioningCallback);
windowDecoration.setDragDetector(touchEventListener.mDragDetector);
windowDecoration.relayout(taskInfo, startT, finishT,
@@ -958,17 +958,17 @@
}
}
- private class TaskCornersListenerImpl
- implements DesktopModeWindowDecoration.TaskCornersListener {
+ private class ExclusionRegionListenerImpl
+ implements ExclusionRegionListener {
@Override
- public void onTaskCornersChanged(int taskId, Region corner) {
- mDesktopTasksController.ifPresent(d -> d.onTaskCornersChanged(taskId, corner));
+ public void onExclusionRegionChanged(int taskId, Region region) {
+ mDesktopTasksController.ifPresent(d -> d.onExclusionRegionChanged(taskId, region));
}
@Override
- public void onTaskCornersRemoved(int taskId) {
- mDesktopTasksController.ifPresent(d -> d.removeCornersForTask(taskId));
+ public void onExclusionRegionDismissed(int taskId) {
+ mDesktopTasksController.ifPresent(d -> d.removeExclusionRegionForTask(taskId));
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index e954f3b..dbff20e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -92,7 +92,7 @@
private Drawable mAppIcon;
private CharSequence mAppName;
- private TaskCornersListener mCornersListener;
+ private ExclusionRegionListener mExclusionRegionListener;
private final Set<IBinder> mTransitionsPausingRelayout = new HashSet<>();
private int mRelayoutBlock;
@@ -128,8 +128,8 @@
mOnCaptionLongClickListener = onLongClickListener;
}
- void setCornersListener(TaskCornersListener cornersListener) {
- mCornersListener = cornersListener;
+ void setExclusionRegionListener(ExclusionRegionListener exclusionRegionListener) {
+ mExclusionRegionListener = exclusionRegionListener;
}
void setDragPositioningCallback(DragPositioningCallback dragPositioningCallback) {
@@ -229,6 +229,10 @@
}
if (!isDragResizeable) {
+ if (!mTaskInfo.positionInParent.equals(mPositionInParent)) {
+ // We still want to track caption bar's exclusion region on a non-resizeable task.
+ updateExclusionRegion();
+ }
closeDragResizeListener();
return;
}
@@ -256,13 +260,13 @@
final int resize_corner = mResult.mRootView.getResources()
.getDimensionPixelSize(R.dimen.freeform_resize_corner);
- // If either task geometry or position have changed, update this task's cornersListener
+ // If either task geometry or position have changed, update this task's
+ // exclusion region listener
if (mDragResizeListener.setGeometry(
mResult.mWidth, mResult.mHeight, resize_handle, resize_corner, touchSlop)
|| !mTaskInfo.positionInParent.equals(mPositionInParent)) {
- mCornersListener.onTaskCornersChanged(mTaskInfo.taskId, getGlobalCornersRegion());
+ updateExclusionRegion();
}
- mPositionInParent.set(mTaskInfo.positionInParent);
if (isMaximizeMenuActive()) {
if (!mTaskInfo.isVisible()) {
@@ -282,8 +286,7 @@
final int displayWidth = displayLayout.width();
final int displayHeight = displayLayout.height();
- final int captionHeight = loadDimensionPixelSize(
- resources, R.dimen.freeform_decor_caption_height);
+ final int captionHeight = getCaptionHeight();
final ImageButton maximizeWindowButton =
mResult.mRootView.findViewById(R.id.maximize_window);
@@ -537,7 +540,7 @@
public void close() {
closeDragResizeListener();
closeHandleMenu();
- mCornersListener.onTaskCornersRemoved(mTaskInfo.taskId);
+ mExclusionRegionListener.onExclusionRegionDismissed(mTaskInfo.taskId);
disposeResizeVeil();
super.close();
}
@@ -548,13 +551,32 @@
: R.layout.desktop_mode_focused_window_decor;
}
+ private void updatePositionInParent() {
+ mPositionInParent.set(mTaskInfo.positionInParent);
+ }
+
+ private void updateExclusionRegion() {
+ // An outdated position in parent is one reason for this to be called; update it here.
+ updatePositionInParent();
+ mExclusionRegionListener
+ .onExclusionRegionChanged(mTaskInfo.taskId, getGlobalExclusionRegion());
+ }
+
/**
- * Create a new region out of the corner rects of this task.
+ * Create a new exclusion region from the corner rects (if resizeable) and caption bounds
+ * of this task.
*/
- Region getGlobalCornersRegion() {
- Region cornersRegion = mDragResizeListener.getCornersRegion();
- cornersRegion.translate(mPositionInParent.x, mPositionInParent.y);
- return cornersRegion;
+ private Region getGlobalExclusionRegion() {
+ Region exclusionRegion;
+ if (mTaskInfo.isResizeable) {
+ exclusionRegion = mDragResizeListener.getCornersRegion();
+ } else {
+ exclusionRegion = new Region();
+ }
+ exclusionRegion.union(new Rect(0, 0, mResult.mWidth,
+ getCaptionHeight()));
+ exclusionRegion.translate(mPositionInParent.x, mPositionInParent.y);
+ return exclusionRegion;
}
/**
@@ -572,6 +594,10 @@
return R.dimen.freeform_decor_caption_height;
}
+ private int getCaptionHeight() {
+ return loadDimensionPixelSize(mContext.getResources(), getCaptionHeightId());
+ }
+
/**
* Add transition to mTransitionsPausingRelayout
*/
@@ -626,12 +652,14 @@
}
}
- interface TaskCornersListener {
- /** Inform the implementing class of this task's change in corner resize handles */
- void onTaskCornersChanged(int taskId, Region corner);
+ interface ExclusionRegionListener {
+ /** Inform the implementing class of this task's change in region resize handles */
+ void onExclusionRegionChanged(int taskId, Region region);
- /** Inform the implementing class that this task no longer needs its corners tracked,
- * likely due to it closing. */
- void onTaskCornersRemoved(int taskId);
+ /**
+ * Inform the implementing class that this task no longer needs an exclusion region,
+ * likely due to it closing.
+ */
+ void onExclusionRegionDismissed(int taskId);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
index bfce72b..09fc3da 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
@@ -49,11 +49,13 @@
private final Supplier<SurfaceControl.Builder> mSurfaceControlBuilderSupplier;
private final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
private final Drawable mAppIcon;
+ private ImageView mIconView;
private SurfaceControl mParentSurface;
private SurfaceControl mVeilSurface;
private final RunningTaskInfo mTaskInfo;
private SurfaceControlViewHost mViewHost;
private final Display mDisplay;
+ private ValueAnimator mVeilAnimator;
public ResizeVeil(Context context, Drawable appIcon, RunningTaskInfo taskInfo,
Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier, Display display,
@@ -97,8 +99,8 @@
mViewHost = new SurfaceControlViewHost(mContext, mDisplay, windowManager, "ResizeVeil");
mViewHost.setView(v, lp);
- final ImageView appIcon = mViewHost.getView().findViewById(R.id.veil_application_icon);
- appIcon.setImageDrawable(mAppIcon);
+ mIconView = mViewHost.getView().findViewById(R.id.veil_application_icon);
+ mIconView.setImageDrawable(mAppIcon);
}
/**
@@ -123,17 +125,27 @@
relayout(taskBounds, t);
if (fadeIn) {
- final ValueAnimator animator = new ValueAnimator();
- animator.setFloatValues(0f, 1f);
- animator.setDuration(RESIZE_ALPHA_DURATION);
- animator.addUpdateListener(animation -> {
- t.setAlpha(mVeilSurface, animator.getAnimatedFraction());
+ mVeilAnimator = new ValueAnimator();
+ mVeilAnimator.setFloatValues(0f, 1f);
+ mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION);
+ mVeilAnimator.addUpdateListener(animation -> {
+ t.setAlpha(mVeilSurface, mVeilAnimator.getAnimatedFraction());
t.apply();
});
+ final ValueAnimator iconAnimator = new ValueAnimator();
+ iconAnimator.setFloatValues(0f, 1f);
+ iconAnimator.setDuration(RESIZE_ALPHA_DURATION);
+ iconAnimator.addUpdateListener(animation -> {
+ mIconView.setAlpha(animation.getAnimatedFraction());
+ });
+
t.show(mVeilSurface)
.addTransactionCommittedListener(
- mContext.getMainExecutor(), () -> animator.start())
+ mContext.getMainExecutor(), () -> {
+ mVeilAnimator.start();
+ iconAnimator.start();
+ })
.setAlpha(mVeilSurface, 0);
} else {
// Show the veil immediately at full opacity.
@@ -172,11 +184,17 @@
/**
* Calls relayout to update task and veil bounds.
+ * Finishes veil fade in if animation is currently running; this is to prevent empty space
+ * being visible behind the transparent veil during a fast resize.
*
* @param t a transaction to be applied in sync with the veil draw.
* @param newBounds bounds to update veil to.
*/
public void updateResizeVeil(SurfaceControl.Transaction t, Rect newBounds) {
+ if (mVeilAnimator != null && mVeilAnimator.isStarted()) {
+ // TODO(b/300145351): Investigate why ValueAnimator#end does not work here.
+ mVeilAnimator.setCurrentPlayTime(RESIZE_ALPHA_DURATION);
+ }
relayout(newBounds, t);
mViewHost.getView().getViewRootImpl().applyTransactionOnDraw(t);
}
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index eb650ca..6fd3354 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -44,6 +44,16 @@
}
filegroup {
+ name: "WMShellFlickerTestsPipCommon-src",
+ srcs: ["src/com/android/wm/shell/flicker/pip/common/*.kt"],
+}
+
+filegroup {
+ name: "WMShellFlickerTestsPipApps-src",
+ srcs: ["src/com/android/wm/shell/flicker/pip/apps/*.kt"],
+}
+
+filegroup {
name: "WMShellFlickerTestsSplitScreenBase-src",
srcs: [
"src/com/android/wm/shell/flicker/splitscreen/benchmark/*.kt",
@@ -152,6 +162,8 @@
exclude_srcs: [
":WMShellFlickerTestsBubbles-src",
":WMShellFlickerTestsPip-src",
+ ":WMShellFlickerTestsPipCommon-src",
+ ":WMShellFlickerTestsPipApps-src",
":WMShellFlickerTestsSplitScreenGroup1-src",
":WMShellFlickerTestsSplitScreenGroup2-src",
":WMShellFlickerTestsSplitScreenBase-src",
@@ -181,6 +193,20 @@
srcs: [
":WMShellFlickerTestsBase-src",
":WMShellFlickerTestsPip-src",
+ ":WMShellFlickerTestsPipCommon-src",
+ ],
+}
+
+android_test {
+ name: "WMShellFlickerTestsPipApps",
+ defaults: ["WMShellFlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestPip.xml"],
+ package_name: "com.android.wm.shell.flicker.pip.apps",
+ instrumentation_target_package: "com.android.wm.shell.flicker.pip.apps",
+ srcs: [
+ ":WMShellFlickerTestsBase-src",
+ ":WMShellFlickerTestsPipApps-src",
+ ":WMShellFlickerTestsPipCommon-src",
],
}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
index 57df4e8..b13e9a2 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
@@ -60,9 +60,9 @@
<!-- Enable mocking GPS location by the test app -->
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command"
- value="appops set com.android.wm.shell.flicker.pip android:mock_location allow"/>
+ value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location allow"/>
<option name="teardown-command"
- value="appops set com.android.wm.shell.flicker.pip android:mock_location deny"/>
+ value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location deny"/>
</target_preparer>
<!-- Needed for pushing the trace config file -->
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
index ca28f52..9256725 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
@@ -21,6 +21,7 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.flicker.pip.common.ClosePipTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
index 4da628c..002c019 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
@@ -20,6 +20,7 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.flicker.pip.common.ClosePipTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index e0b18de..6dd68b0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -20,6 +20,7 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.flicker.pip.common.EnterPipTransition
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index b4cedd9..8207b85 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -32,8 +32,9 @@
import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP
import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
-import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
-import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
+import com.android.wm.shell.flicker.pip.common.PipTransition
+import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
+import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
index f9efffe..cc94367 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
@@ -19,6 +19,7 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.flicker.pip.common.EnterPipTransition
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
index c4e63c3..7da4429 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
@@ -19,6 +19,7 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
index 839bbd4..0ad9e4c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
@@ -19,6 +19,7 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index ea67e3d..89a6c93 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -23,6 +23,7 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
index 0f30cef..8978af0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
@@ -22,6 +22,7 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
index 421ad75..4776206 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
@@ -21,6 +21,7 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition
import com.android.wm.shell.flicker.utils.Direction
import org.junit.FixMethodOrder
import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
index c10860a..425cbfaff 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
@@ -27,6 +27,7 @@
import android.tools.device.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.helpers.setRotation
+import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
index 992f1bc..18f30d9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
@@ -21,6 +21,7 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition
import com.android.wm.shell.flicker.utils.Direction
import org.junit.FixMethodOrder
import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
index 0c6fc56..c7f2786 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
@@ -23,6 +23,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index 43e7696..cabc1cc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -27,6 +27,7 @@
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
index 0295741..6748626 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
@@ -23,6 +23,7 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
index a236126..1f69847 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
@@ -30,7 +30,8 @@
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
-import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
+import com.android.wm.shell.flicker.pip.common.PipTransition
+import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import org.junit.Assume
import org.junit.Before
import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
index e588f87..308ece4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
@@ -25,6 +25,7 @@
import android.tools.device.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.setRotation
+import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppsEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
similarity index 98%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppsEnterPipTransition.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
index 9a28439..fb6c093 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppsEnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.pip
+package com.android.wm.shell.flicker.pip.apps
import android.platform.test.annotations.Postsubmit
import android.tools.common.Rotation
@@ -22,6 +22,7 @@
import android.tools.device.apphelpers.StandardAppHelper
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import com.android.wm.shell.flicker.pip.common.EnterPipTransition
import org.junit.Test
import org.junit.runners.Parameterized
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MapsEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
similarity index 98%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MapsEnterPipTest.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
index 258c0588..54b3e2a8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MapsEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.pip
+package com.android.wm.shell.flicker.pip.apps
import android.os.Handler
import android.os.Looper
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
similarity index 96%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
index a17144b..751f2bc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.pip
+package com.android.wm.shell.flicker.pip.common
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
similarity index 98%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
index d547b9c..9c129e4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.pip
+package com.android.wm.shell.flicker.pip.common
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
similarity index 97%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
index dfffba8..9450bdd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.pip
+package com.android.wm.shell.flicker.pip.common
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt
similarity index 97%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt
index a8fb63d..7e42bc1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.pip
+package com.android.wm.shell.flicker.pip.common
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
similarity index 97%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
index 2008d01..7b7f1d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.pip
+package com.android.wm.shell.flicker.pip.common
import android.app.Instrumentation
import android.content.Intent
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
index 00f6073..4ff0b4362 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
@@ -31,7 +31,7 @@
class SwitchBackToSplitFromRecentGesturalNavLandscape :
SwitchBackToSplitFromRecent(Rotation.ROTATION_90) {
- @ExpectedScenarios(["QUICKSWITCH"])
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
@Test
override fun switchBackToSplitFromRecent() = super.switchBackToSplitFromRecent()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
index b3340e7..930f31d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
@@ -31,7 +31,7 @@
class SwitchBackToSplitFromRecentGesturalNavPortrait :
SwitchBackToSplitFromRecent(Rotation.ROTATION_0) {
- @ExpectedScenarios(["QUICKSWITCH"])
+ @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
@Test
override fun switchBackToSplitFromRecent() = super.switchBackToSplitFromRecent()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
index f4e7298..c744103 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
@@ -29,7 +29,7 @@
@RunWith(FlickerServiceJUnit4ClassRunner::class)
class UnlockKeyguardToSplitScreenGesturalNavLandscape : UnlockKeyguardToSplitScreen() {
- @ExpectedScenarios(["QUICKSWITCH"])
+ @ExpectedScenarios(["LOCKSCREEN_UNLOCK_ANIMATION"])
@Test
override fun unlockKeyguardToSplitScreen() = super.unlockKeyguardToSplitScreen()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
index f38b2e8..11a4e02 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
@@ -29,7 +29,7 @@
@RunWith(FlickerServiceJUnit4ClassRunner::class)
class UnlockKeyguardToSplitScreenGesturalNavPortrait : UnlockKeyguardToSplitScreen() {
- @ExpectedScenarios(["QUICKSWITCH"])
+ @ExpectedScenarios(["LOCKSCREEN_UNLOCK_ANIMATION"])
@Test
override fun unlockKeyguardToSplitScreen() = super.unlockKeyguardToSplitScreen()
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index ce6b4b7..502ff87 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -737,6 +737,7 @@
"tests/unit/EglManagerTests.cpp",
"tests/unit/FatVectorTests.cpp",
"tests/unit/GraphicsStatsServiceTests.cpp",
+ "tests/unit/HintSessionWrapperTests.cpp",
"tests/unit/JankTrackerTests.cpp",
"tests/unit/FrameMetricsReporterTests.cpp",
"tests/unit/LayerUpdateQueueTests.cpp",
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 19a1dfa..16de21d 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -22,6 +22,7 @@
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
#include <GrDirectContext.h>
+#include <GrTypes.h>
#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkImage.h>
@@ -265,7 +266,7 @@
sk_sp<SkImage> image =
SkImages::TextureFromAHardwareBufferWithData(mGrContext.get(), bitmap.pixmap(),
ahb);
- mGrContext->submit(true);
+ mGrContext->submit(GrSyncCpu::kYes);
uploadSucceeded = (image.get() != nullptr);
});
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 8f81dba..735fc07 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -17,6 +17,7 @@
#include "CacheManager.h"
#include <GrContextOptions.h>
+#include <GrTypes.h>
#include <SkExecutor.h>
#include <SkGraphics.h>
#include <math.h>
@@ -110,13 +111,18 @@
contextOptions->fPersistentCache = &cache;
}
+static GrPurgeResourceOptions toSkiaEnum(bool scratchOnly) {
+ return scratchOnly ? GrPurgeResourceOptions::kScratchResourcesOnly :
+ GrPurgeResourceOptions::kAllResources;
+}
+
void CacheManager::trimMemory(TrimLevel mode) {
if (!mGrContext) {
return;
}
// flush and submit all work to the gpu and wait for it to finish
- mGrContext->flushAndSubmit(/*syncCpu=*/true);
+ mGrContext->flushAndSubmit(GrSyncCpu::kYes);
switch (mode) {
case TrimLevel::BACKGROUND:
@@ -130,7 +136,7 @@
// that have persistent data to be purged in LRU order.
mGrContext->setResourceCacheLimit(mBackgroundResourceBytes);
SkGraphics::SetFontCacheLimit(mBackgroundCpuFontCacheBytes);
- mGrContext->purgeUnlockedResources(mMemoryPolicy.purgeScratchOnly);
+ mGrContext->purgeUnlockedResources(toSkiaEnum(mMemoryPolicy.purgeScratchOnly));
mGrContext->setResourceCacheLimit(mMaxResourceBytes);
SkGraphics::SetFontCacheLimit(mMaxCpuFontCacheBytes);
break;
@@ -150,7 +156,7 @@
case CacheTrimLevel::ALL_CACHES:
SkGraphics::PurgeAllCaches();
if (mGrContext) {
- mGrContext->purgeUnlockedResources(false);
+ mGrContext->purgeUnlockedResources(GrPurgeResourceOptions::kAllResources);
}
break;
default:
@@ -285,7 +291,7 @@
ns2ms(std::clamp(frameDiffNanos, mMemoryPolicy.minimumResourceRetention,
mMemoryPolicy.maximumResourceRetention));
mGrContext->performDeferredCleanup(std::chrono::milliseconds(cleanupMillis),
- mMemoryPolicy.purgeScratchOnly);
+ toSkiaEnum(mMemoryPolicy.purgeScratchOnly));
}
}
diff --git a/libs/hwui/renderthread/HintSessionWrapper.cpp b/libs/hwui/renderthread/HintSessionWrapper.cpp
index 1f338ee..b34da51 100644
--- a/libs/hwui/renderthread/HintSessionWrapper.cpp
+++ b/libs/hwui/renderthread/HintSessionWrapper.cpp
@@ -32,65 +32,30 @@
namespace uirenderer {
namespace renderthread {
-namespace {
+#define BIND_APH_METHOD(name) \
+ name = (decltype(name))dlsym(handle_, "APerformanceHint_" #name); \
+ LOG_ALWAYS_FATAL_IF(name == nullptr, "Failed to find required symbol APerformanceHint_" #name)
-typedef APerformanceHintManager* (*APH_getManager)();
-typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*,
- size_t, int64_t);
-typedef void (*APH_closeSession)(APerformanceHintSession* session);
-typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
-typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
-typedef void (*APH_sendHint)(APerformanceHintSession* session, int32_t);
-
-bool gAPerformanceHintBindingInitialized = false;
-APH_getManager gAPH_getManagerFn = nullptr;
-APH_createSession gAPH_createSessionFn = nullptr;
-APH_closeSession gAPH_closeSessionFn = nullptr;
-APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
-APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
-APH_sendHint gAPH_sendHintFn = nullptr;
-
-void ensureAPerformanceHintBindingInitialized() {
- if (gAPerformanceHintBindingInitialized) return;
+void HintSessionWrapper::HintSessionBinding::init() {
+ if (mInitialized) return;
void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
- gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager");
- LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr,
- "Failed to find required symbol APerformanceHint_getManager!");
+ BIND_APH_METHOD(getManager);
+ BIND_APH_METHOD(createSession);
+ BIND_APH_METHOD(closeSession);
+ BIND_APH_METHOD(updateTargetWorkDuration);
+ BIND_APH_METHOD(reportActualWorkDuration);
+ BIND_APH_METHOD(sendHint);
- gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
- LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
- "Failed to find required symbol APerformanceHint_createSession!");
-
- gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
- LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
- "Failed to find required symbol APerformanceHint_closeSession!");
-
- gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym(
- handle_, "APerformanceHint_updateTargetWorkDuration");
- LOG_ALWAYS_FATAL_IF(
- gAPH_updateTargetWorkDurationFn == nullptr,
- "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!");
-
- gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym(
- handle_, "APerformanceHint_reportActualWorkDuration");
- LOG_ALWAYS_FATAL_IF(
- gAPH_reportActualWorkDurationFn == nullptr,
- "Failed to find required symbol APerformanceHint_reportActualWorkDuration!");
-
- gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint");
- LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr,
- "Failed to find required symbol APerformanceHint_sendHint!");
-
- gAPerformanceHintBindingInitialized = true;
+ mInitialized = true;
}
-} // namespace
-
HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId)
- : mUiThreadId(uiThreadId), mRenderThreadId(renderThreadId) {}
+ : mUiThreadId(uiThreadId)
+ , mRenderThreadId(renderThreadId)
+ , mBinding(std::make_shared<HintSessionBinding>()) {}
HintSessionWrapper::~HintSessionWrapper() {
destroy();
@@ -101,7 +66,7 @@
mHintSession = mHintSessionFuture.get();
}
if (mHintSession) {
- gAPH_closeSessionFn(mHintSession);
+ mBinding->closeSession(mHintSession);
mSessionValid = true;
mHintSession = nullptr;
}
@@ -133,9 +98,9 @@
// Assume that if we return before the end, it broke
mSessionValid = false;
- ensureAPerformanceHintBindingInitialized();
+ mBinding->init();
- APerformanceHintManager* manager = gAPH_getManagerFn();
+ APerformanceHintManager* manager = mBinding->getManager();
if (!manager) return false;
std::vector<pid_t> tids = CommonPool::getThreadIds();
@@ -145,8 +110,9 @@
// Use a placeholder target value to initialize,
// this will always be replaced elsewhere before it gets used
int64_t defaultTargetDurationNanos = 16666667;
- mHintSessionFuture = CommonPool::async([=, tids = std::move(tids)] {
- return gAPH_createSessionFn(manager, tids.data(), tids.size(), defaultTargetDurationNanos);
+ mHintSessionFuture = CommonPool::async([=, this, tids = std::move(tids)] {
+ return mBinding->createSession(manager, tids.data(), tids.size(),
+ defaultTargetDurationNanos);
});
return false;
}
@@ -158,7 +124,7 @@
targetWorkDurationNanos > kSanityCheckLowerBound &&
targetWorkDurationNanos < kSanityCheckUpperBound) {
mLastTargetWorkDuration = targetWorkDurationNanos;
- gAPH_updateTargetWorkDurationFn(mHintSession, targetWorkDurationNanos);
+ mBinding->updateTargetWorkDuration(mHintSession, targetWorkDurationNanos);
}
mLastFrameNotification = systemTime();
}
@@ -168,7 +134,7 @@
mResetsSinceLastReport = 0;
if (actualDurationNanos > kSanityCheckLowerBound &&
actualDurationNanos < kSanityCheckUpperBound) {
- gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos);
+ mBinding->reportActualWorkDuration(mHintSession, actualDurationNanos);
}
}
@@ -179,14 +145,14 @@
if (now - mLastFrameNotification > kResetHintTimeout &&
mResetsSinceLastReport <= kMaxResetsSinceLastReport) {
++mResetsSinceLastReport;
- gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_RESET));
+ mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET));
}
mLastFrameNotification = now;
}
void HintSessionWrapper::sendLoadIncreaseHint() {
if (!init()) return;
- gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_UP));
+ mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_UP));
}
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/HintSessionWrapper.h b/libs/hwui/renderthread/HintSessionWrapper.h
index bdb9959..f8b876e 100644
--- a/libs/hwui/renderthread/HintSessionWrapper.h
+++ b/libs/hwui/renderthread/HintSessionWrapper.h
@@ -29,6 +29,8 @@
class HintSessionWrapper {
public:
+ friend class HintSessionWrapperTests;
+
HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId);
~HintSessionWrapper();
@@ -55,6 +57,28 @@
static constexpr nsecs_t kResetHintTimeout = 100_ms;
static constexpr int64_t kSanityCheckLowerBound = 100_us;
static constexpr int64_t kSanityCheckUpperBound = 10_s;
+
+ // Allows easier stub when testing
+ class HintSessionBinding {
+ public:
+ virtual ~HintSessionBinding() = default;
+ virtual void init();
+ APerformanceHintManager* (*getManager)();
+ APerformanceHintSession* (*createSession)(APerformanceHintManager* manager,
+ const int32_t* tids, size_t tidCount,
+ int64_t defaultTarget) = nullptr;
+ void (*closeSession)(APerformanceHintSession* session) = nullptr;
+ void (*updateTargetWorkDuration)(APerformanceHintSession* session,
+ int64_t targetDuration) = nullptr;
+ void (*reportActualWorkDuration)(APerformanceHintSession* session,
+ int64_t actualDuration) = nullptr;
+ void (*sendHint)(APerformanceHintSession* session, int32_t hintId) = nullptr;
+
+ private:
+ bool mInitialized = false;
+ };
+
+ std::shared_ptr<HintSessionBinding> mBinding;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index ee3b2e4..90850d3 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -515,7 +515,7 @@
// The following flush blocks the GPU immediately instead of waiting for
// other drawing ops. It seems dequeue_fence is not respected otherwise.
// TODO: remove the flush after finding why backendSemaphore is not working.
- skgpu::ganesh::FlushAndSubmit(bufferInfo->skSurface);
+ skgpu::ganesh::FlushAndSubmit(bufferInfo->skSurface.get());
}
}
}
diff --git a/libs/hwui/tests/unit/HintSessionWrapperTests.cpp b/libs/hwui/tests/unit/HintSessionWrapperTests.cpp
new file mode 100644
index 0000000..623be1e
--- /dev/null
+++ b/libs/hwui/tests/unit/HintSessionWrapperTests.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <private/performance_hint_private.h>
+#include <renderthread/HintSessionWrapper.h>
+#include <utils/Log.h>
+
+#include <chrono>
+
+#include "Properties.h"
+
+using namespace testing;
+using namespace std::chrono_literals;
+
+APerformanceHintManager* managerPtr = reinterpret_cast<APerformanceHintManager*>(123);
+APerformanceHintSession* sessionPtr = reinterpret_cast<APerformanceHintSession*>(456);
+int uiThreadId = 1;
+int renderThreadId = 2;
+
+namespace android::uirenderer::renderthread {
+
+class HintSessionWrapperTests : public testing::Test {
+public:
+ void SetUp() override;
+ void TearDown() override;
+
+protected:
+ std::shared_ptr<HintSessionWrapper> mWrapper;
+
+ class MockHintSessionBinding : public HintSessionWrapper::HintSessionBinding {
+ public:
+ void init() override;
+
+ MOCK_METHOD(APerformanceHintManager*, fakeGetManager, ());
+ MOCK_METHOD(APerformanceHintSession*, fakeCreateSession,
+ (APerformanceHintManager*, const int32_t*, size_t, int64_t));
+ MOCK_METHOD(void, fakeCloseSession, (APerformanceHintSession*));
+ MOCK_METHOD(void, fakeUpdateTargetWorkDuration, (APerformanceHintSession*, int64_t));
+ MOCK_METHOD(void, fakeReportActualWorkDuration, (APerformanceHintSession*, int64_t));
+ MOCK_METHOD(void, fakeSendHint, (APerformanceHintSession*, int32_t));
+ };
+
+ // Must be static so it can have function pointers we can point to with static methods
+ static std::shared_ptr<MockHintSessionBinding> sMockBinding;
+
+ // Must be static so we can point to them as normal fn pointers with HintSessionBinding
+ static APerformanceHintManager* stubGetManager() { return sMockBinding->fakeGetManager(); };
+ static APerformanceHintSession* stubCreateSession(APerformanceHintManager* manager,
+ const int32_t* ids, size_t idsSize,
+ int64_t initialTarget) {
+ return sMockBinding->fakeCreateSession(manager, ids, idsSize, initialTarget);
+ }
+ static APerformanceHintSession* stubSlowCreateSession(APerformanceHintManager* manager,
+ const int32_t* ids, size_t idsSize,
+ int64_t initialTarget) {
+ std::this_thread::sleep_for(50ms);
+ return sMockBinding->fakeCreateSession(manager, ids, idsSize, initialTarget);
+ }
+ static void stubCloseSession(APerformanceHintSession* session) {
+ sMockBinding->fakeCloseSession(session);
+ };
+ static void stubUpdateTargetWorkDuration(APerformanceHintSession* session,
+ int64_t workDuration) {
+ sMockBinding->fakeUpdateTargetWorkDuration(session, workDuration);
+ }
+ static void stubReportActualWorkDuration(APerformanceHintSession* session,
+ int64_t workDuration) {
+ sMockBinding->fakeReportActualWorkDuration(session, workDuration);
+ }
+ static void stubSendHint(APerformanceHintSession* session, int32_t hintId) {
+ sMockBinding->fakeSendHint(session, hintId);
+ };
+ void waitForWrapperReady() { mWrapper->mHintSessionFuture.wait(); }
+};
+
+std::shared_ptr<HintSessionWrapperTests::MockHintSessionBinding>
+ HintSessionWrapperTests::sMockBinding;
+
+void HintSessionWrapperTests::SetUp() {
+ // Pretend it's supported even if we're in an emulator
+ Properties::useHintManager = true;
+ sMockBinding = std::make_shared<NiceMock<MockHintSessionBinding>>();
+ mWrapper = std::make_shared<HintSessionWrapper>(uiThreadId, renderThreadId);
+ mWrapper->mBinding = sMockBinding;
+ EXPECT_CALL(*sMockBinding, fakeGetManager).WillOnce(Return(managerPtr));
+ ON_CALL(*sMockBinding, fakeCreateSession).WillByDefault(Return(sessionPtr));
+}
+
+void HintSessionWrapperTests::MockHintSessionBinding::init() {
+ sMockBinding->getManager = &stubGetManager;
+ if (sMockBinding->createSession == nullptr) {
+ sMockBinding->createSession = &stubCreateSession;
+ }
+ sMockBinding->closeSession = &stubCloseSession;
+ sMockBinding->updateTargetWorkDuration = &stubUpdateTargetWorkDuration;
+ sMockBinding->reportActualWorkDuration = &stubReportActualWorkDuration;
+ sMockBinding->sendHint = &stubSendHint;
+}
+
+void HintSessionWrapperTests::TearDown() {
+ mWrapper = nullptr;
+ sMockBinding = nullptr;
+}
+
+TEST_F(HintSessionWrapperTests, destructorClosesBackgroundSession) {
+ EXPECT_CALL(*sMockBinding, fakeCloseSession(sessionPtr)).Times(1);
+ sMockBinding->createSession = stubSlowCreateSession;
+ mWrapper->init();
+ mWrapper = nullptr;
+}
+
+TEST_F(HintSessionWrapperTests, sessionInitializesCorrectly) {
+ EXPECT_CALL(*sMockBinding, fakeCreateSession(managerPtr, _, Gt(1), _)).Times(1);
+ mWrapper->init();
+ waitForWrapperReady();
+}
+
+TEST_F(HintSessionWrapperTests, loadUpHintsSendCorrectly) {
+ EXPECT_CALL(*sMockBinding,
+ fakeSendHint(sessionPtr, static_cast<int32_t>(SessionHint::CPU_LOAD_UP)))
+ .Times(1);
+ mWrapper->init();
+ waitForWrapperReady();
+ mWrapper->sendLoadIncreaseHint();
+}
+
+TEST_F(HintSessionWrapperTests, loadResetHintsSendCorrectly) {
+ EXPECT_CALL(*sMockBinding,
+ fakeSendHint(sessionPtr, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET)))
+ .Times(1);
+ mWrapper->init();
+ waitForWrapperReady();
+ mWrapper->sendLoadResetHint();
+}
+
+} // namespace android::uirenderer::renderthread
\ No newline at end of file
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index 17962ee..86e53f5 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -1,8 +1,15 @@
package: "com.android.media.flags"
flag {
- namespace: "media_solutions"
- name: "enable_rlp_callbacks_in_media_router2"
- description: "Make RouteListingPreference getter and callbacks public in MediaRouter2."
- bug: "281067101"
+ name: "enable_rlp_callbacks_in_media_router2"
+ namespace: "media_solutions"
+ description: "Make RouteListingPreference getter and callbacks public in MediaRouter2."
+ bug: "281067101"
+}
+
+flag {
+ name: "adjust_volume_for_foreground_app_playing_audio_without_media_session"
+ namespace: "media_solutions"
+ description: "Gates whether to adjust local stream volume when the app in the foreground is the last app to play audio or adjust the volume of the last active media session that the user interacted with."
+ bug: "275185436"
}
diff --git a/packages/CredentialManager/horologist/OWNERS b/packages/CredentialManager/horologist/OWNERS
new file mode 100644
index 0000000..b679328
--- /dev/null
+++ b/packages/CredentialManager/horologist/OWNERS
@@ -0,0 +1,4 @@
+include /core/java/android/credentials/OWNERS
+
+shuanghao@google.com
+gustavopagani@google.com
diff --git a/packages/CredentialManager/shared/OWNERS b/packages/CredentialManager/shared/OWNERS
new file mode 100644
index 0000000..b679328
--- /dev/null
+++ b/packages/CredentialManager/shared/OWNERS
@@ -0,0 +1,4 @@
+include /core/java/android/credentials/OWNERS
+
+shuanghao@google.com
+gustavopagani@google.com
diff --git a/packages/CredentialManager/wear/OWNERS b/packages/CredentialManager/wear/OWNERS
new file mode 100644
index 0000000..b679328
--- /dev/null
+++ b/packages/CredentialManager/wear/OWNERS
@@ -0,0 +1,4 @@
+include /core/java/android/credentials/OWNERS
+
+shuanghao@google.com
+gustavopagani@google.com
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index ec24ab7..8dc95f4 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1665,14 +1665,6 @@
<!-- Developer setting: enable animations when a back gesture is executed, full explanation[CHAR LIMIT=NONE] -->
<string name="back_navigation_animation_dialog">This setting enables system animations for predictive gesture animation. It requires setting per-app "enableOnBackInvokedCallback" to true in the manifest file.</string>
- <!-- [CHAR LIMIT=NONE] Messages shown when users press outside of udfps region during -->
- <string-array name="udfps_accessibility_touch_hints">
- <item>Move left</item>
- <item>Move down</item>
- <item>Move right</item>
- <item>Move up</item>
- </string-array>
-
<!-- Formatting states for the scale of font size, in percent. Double "%" is required to represent the symbol "%". [CHAR LIMIT=20] -->
<string name="font_scale_percentage"> <xliff:g id="percentage">%1$d</xliff:g> %%</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index ff960f3..03d1cda 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -20,6 +20,8 @@
import static android.app.admin.DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY;
import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+import static com.android.settingslib.Utils.getColorAttrDefaultColor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -125,7 +127,8 @@
return null;
}
- final EnforcedAdmin admin = getProfileOrDeviceOwner(context, enforcingUser.getUserHandle());
+ final EnforcedAdmin admin =
+ getProfileOrDeviceOwner(context, userRestriction, enforcingUser.getUserHandle());
if (admin != null) {
return admin;
}
@@ -638,7 +641,8 @@
removeExistingRestrictedSpans(sb);
if (admin != null) {
- final int disabledColor = context.getColor(R.color.disabled_text_color);
+ final int disabledColor = getColorAttrDefaultColor(context,
+ android.R.attr.textColorHint);
sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ImageSpan image = new RestrictedLockImageSpan(context);
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index dcb0a07..8b0f19d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -17,7 +17,6 @@
package com.android.settingslib;
import static android.app.admin.DevicePolicyResources.Strings.Settings.CONTROLLED_BY_ADMIN_SUMMARY;
-
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.admin.DevicePolicyManager;
@@ -32,6 +31,7 @@
import android.widget.TextView;
import androidx.annotation.RequiresApi;
+import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
@@ -48,7 +48,8 @@
int uid;
private boolean mDisabledByAdmin;
- private EnforcedAdmin mEnforcedAdmin;
+ @VisibleForTesting
+ EnforcedAdmin mEnforcedAdmin;
private String mAttrUserRestriction = null;
private boolean mDisabledSummary = false;
@@ -193,8 +194,14 @@
* @return true if the disabled state was changed.
*/
public boolean setDisabledByAdmin(EnforcedAdmin admin) {
- final boolean disabled = (admin != null ? true : false);
- mEnforcedAdmin = admin;
+ boolean disabled = false;
+ mEnforcedAdmin = null;
+ if (admin != null) {
+ disabled = true;
+ // Copy the received instance to prevent pass be reference being overwritten.
+ mEnforcedAdmin = new EnforcedAdmin(admin);
+ }
+
boolean changed = false;
if (mDisabledByAdmin != disabled) {
mDisabledByAdmin = disabled;
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 9d533fa..412a342 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -549,7 +549,12 @@
/**
* Return the combined service state.
- * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI
+ * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI.
+ *
+ * This method returns a single service state int if either the voice reg state is
+ * {@link ServiceState#STATE_IN_SERVICE} or if data network is registered via a
+ * WWAN transport type. We consider the combined service state of an IWLAN network
+ * to be OOS.
*
* @param serviceState Service state. {@link ServiceState}
*/
@@ -558,23 +563,37 @@
return ServiceState.STATE_OUT_OF_SERVICE;
}
- // Consider the device to be in service if either voice or data
- // service is available. Some SIM cards are marketed as data-only
- // and do not support voice service, and on these SIM cards, we
- // want to show signal bars for data service as well as the "no
- // service" or "emergency calls only" text that indicates that voice
- // is not available. Note that we ignore the IWLAN service state
- // because that state indicates the use of VoWIFI and not cell service
- final int state = serviceState.getState();
- final int dataState = serviceState.getDataRegistrationState();
+ final int voiceRegState = serviceState.getVoiceRegState();
- if (state == ServiceState.STATE_OUT_OF_SERVICE
- || state == ServiceState.STATE_EMERGENCY_ONLY) {
- if (dataState == ServiceState.STATE_IN_SERVICE && isNotInIwlan(serviceState)) {
+ // Consider a mobile connection to be "in service" if either voice is IN_SERVICE
+ // or the data registration reports IN_SERVICE on a transport type of WWAN. This
+ // effectively excludes the IWLAN condition. IWLAN connections imply service via
+ // Wi-Fi rather than cellular, and so we do not consider these transports when
+ // determining if cellular is "in service".
+
+ if (voiceRegState == ServiceState.STATE_OUT_OF_SERVICE
+ || voiceRegState == ServiceState.STATE_EMERGENCY_ONLY) {
+ if (isDataRegInWwanAndInService(serviceState)) {
return ServiceState.STATE_IN_SERVICE;
}
}
- return state;
+
+ return voiceRegState;
+ }
+
+ // ServiceState#mDataRegState can be set to IN_SERVICE if the network is registered
+ // on either a WLAN or WWAN network. Since we want to exclude the WLAN network, we can
+ // query the WWAN network directly and check for its registration state
+ private static boolean isDataRegInWwanAndInService(ServiceState serviceState) {
+ final NetworkRegistrationInfo networkRegWwan = serviceState.getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ if (networkRegWwan == null) {
+ return false;
+ }
+
+ return networkRegWwan.isInService();
}
/** Get the corresponding adaptive icon drawable. */
@@ -598,21 +617,6 @@
UserHandle.getUserHandleForUid(appInfo.uid));
}
- private static boolean isNotInIwlan(ServiceState serviceState) {
- final NetworkRegistrationInfo networkRegWlan = serviceState.getNetworkRegistrationInfo(
- NetworkRegistrationInfo.DOMAIN_PS,
- AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
- if (networkRegWlan == null) {
- return true;
- }
-
- final boolean isInIwlan = (networkRegWlan.getRegistrationState()
- == NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
- || (networkRegWlan.getRegistrationState()
- == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
- return !isInIwlan;
- }
-
/**
* Returns a bitmap with rounded corner.
*
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
index f90a17a..7f1f3f6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -40,9 +40,7 @@
* Stores and computes some battery information.
*/
public class BatteryStatus {
- private static final int LOW_BATTERY_THRESHOLD = 20;
- private static final int SEVERE_LOW_BATTERY_THRESHOLD = 10;
- private static final int EXTREME_LOW_BATTERY_THRESHOLD = 3;
+
private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
public static final int BATTERY_LEVEL_UNKNOWN = -1;
@@ -50,6 +48,9 @@
public static final int CHARGING_SLOWLY = 0;
public static final int CHARGING_REGULAR = 1;
public static final int CHARGING_FAST = 2;
+ public static final int LOW_BATTERY_THRESHOLD = 20;
+ public static final int SEVERE_LOW_BATTERY_THRESHOLD = 10;
+ public static final int EXTREME_LOW_BATTERY_THRESHOLD = 3;
public final int status;
public final int level;
@@ -197,9 +198,14 @@
: Math.round((level / (float) scale) * 100f);
}
+ /** Returns the plugged type from {@code batteryChangedIntent}. */
+ public static int getPluggedType(Intent batteryChangedIntent) {
+ return batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0);
+ }
+
/** Whether the device is plugged or not. */
public static boolean isPluggedIn(Intent batteryChangedIntent) {
- return isPluggedIn(batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0));
+ return isPluggedIn(getPluggedType(batteryChangedIntent));
}
/** Whether the device is plugged or not. */
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index 94e28f2..a03977c1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -21,11 +21,8 @@
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
-
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -78,6 +75,8 @@
when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE))
.thenReturn(mDevicePolicyManager);
+ when(mContext.getSystemService(DevicePolicyManager.class))
+ .thenReturn(mDevicePolicyManager);
when(mContext.getSystemService(Context.USER_SERVICE))
.thenReturn(mUserManager);
when(mContext.getPackageManager())
@@ -87,14 +86,20 @@
}
@Test
- public void checkIfRestrictionEnforced_deviceOwner() {
+ public void checkIfRestrictionEnforced_deviceOwner()
+ throws PackageManager.NameNotFoundException {
UserManager.EnforcingUser enforcingUser = new UserManager.EnforcingUser(mUserId,
UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS;
when(mUserManager.getUserRestrictionSources(userRestriction,
UserHandle.of(mUserId))).
thenReturn(Collections.singletonList(enforcingUser));
- setUpDeviceOwner(mAdmin1);
+
+ when(mContext.createPackageContextAsUser(any(), eq(0),
+ eq(UserHandle.of(mUserId))))
+ .thenReturn(mContext);
+
+ setUpDeviceOwner(mAdmin1, mUserId);
EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal
.checkIfRestrictionEnforced(mContext, userRestriction, mUserId);
@@ -105,14 +110,20 @@
}
@Test
- public void checkIfRestrictionEnforced_profileOwner() {
+ public void checkIfRestrictionEnforced_profileOwner()
+ throws PackageManager.NameNotFoundException {
UserManager.EnforcingUser enforcingUser = new UserManager.EnforcingUser(mUserId,
UserManager.RESTRICTION_SOURCE_PROFILE_OWNER);
final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS;
when(mUserManager.getUserRestrictionSources(userRestriction,
UserHandle.of(mUserId))).
thenReturn(Collections.singletonList(enforcingUser));
- setUpProfileOwner(mAdmin1, mUserId);
+
+ when(mContext.createPackageContextAsUser(any(), eq(0),
+ eq(UserHandle.of(mUserId))))
+ .thenReturn(mContext);
+
+ setUpProfileOwner(mAdmin1);
EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal
.checkIfRestrictionEnforced(mContext, userRestriction, mUserId);
@@ -326,11 +337,12 @@
.thenReturn(Arrays.asList(activeAdmins));
}
- private void setUpDeviceOwner(ComponentName admin) {
+ private void setUpDeviceOwner(ComponentName admin, int userId) {
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(admin);
+ when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(UserHandle.of(userId));
}
- private void setUpProfileOwner(ComponentName admin, int userId) {
- when(mDevicePolicyManager.getProfileOwnerAsUser(userId)).thenReturn(admin);
+ private void setUpProfileOwner(ComponentName admin) {
+ when(mDevicePolicyManager.getProfileOwner()).thenReturn(admin);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
index 1b0738f..701f008 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
@@ -16,6 +16,7 @@
package com.android.settingslib;
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.doReturn;
@@ -119,4 +120,26 @@
verify(mRestrictedTopLevelPreference, never()).setEnabled(false);
}
+
+ /**
+ * Tests if the instance of {@link RestrictedLockUtils.EnforcedAdmin} is received by
+ * {@link RestrictedPreferenceHelper#setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin)} as a
+ * copy or as a reference.
+ */
+ @Test
+ public void setDisabledByAdmin_disablePreference_receivedEnforcedAdminIsNotAReference() {
+ RestrictedLockUtils.EnforcedAdmin enforcedAdmin =
+ new RestrictedLockUtils.EnforcedAdmin(/* component */ null,
+ /* enforcedRestriction */ "some_restriction",
+ /* userHandle */ null);
+
+ mHelper.setDisabledByAdmin(enforcedAdmin);
+
+ // If `setDisabledByAdmin` stored `enforcedAdmin` as a reference, then the following
+ // assignment would be propagated.
+ enforcedAdmin.enforcedRestriction = null;
+ assertThat(mHelper.mEnforcedAdmin.enforcedRestriction).isEqualTo("some_restriction");
+
+ assertThat(mHelper.isDisabledByAdmin()).isTrue();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index bb72375..29846ac 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -200,47 +200,55 @@
@Test
public void isInService_voiceInService_returnTrue() {
- when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+ when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_IN_SERVICE);
assertThat(Utils.isInService(mServiceState)).isTrue();
}
@Test
public void isInService_voiceOutOfServiceDataInService_returnTrue() {
- when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+ when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
- AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo);
- when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn(
- NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN);
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).thenReturn(mNetworkRegistrationInfo);
+ when(mNetworkRegistrationInfo.isInService()).thenReturn(true);
assertThat(Utils.isInService(mServiceState)).isTrue();
}
@Test
public void isInService_voiceOutOfServiceDataInServiceOnIwLan_returnFalse() {
- when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+ when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo);
- when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn(
- NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+ when(mNetworkRegistrationInfo.isInService()).thenReturn(true);
+
+ assertThat(Utils.isInService(mServiceState)).isFalse();
+ }
+
+ @Test
+ public void isInService_voiceOutOfServiceDataNull_returnFalse() {
+ when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+ when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).thenReturn(null);
assertThat(Utils.isInService(mServiceState)).isFalse();
}
@Test
public void isInService_voiceOutOfServiceDataOutOfService_returnFalse() {
- when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
- when(mServiceState.getDataRegistrationState()).thenReturn(
- ServiceState.STATE_OUT_OF_SERVICE);
+ when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+ when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).thenReturn(mNetworkRegistrationInfo);
+ when(mNetworkRegistrationInfo.isInService()).thenReturn(false);
assertThat(Utils.isInService(mServiceState)).isFalse();
}
@Test
public void isInService_ServiceStatePowerOff_returnFalse() {
- when(mServiceState.getState()).thenReturn(ServiceState.STATE_POWER_OFF);
+ when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_POWER_OFF);
assertThat(Utils.isInService(mServiceState)).isFalse();
}
@@ -253,7 +261,7 @@
@Test
public void getCombinedServiceState_ServiceStatePowerOff_returnPowerOff() {
- when(mServiceState.getState()).thenReturn(ServiceState.STATE_POWER_OFF);
+ when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_POWER_OFF);
assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo(
ServiceState.STATE_POWER_OFF);
@@ -261,7 +269,7 @@
@Test
public void getCombinedServiceState_voiceInService_returnInService() {
- when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+ when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_IN_SERVICE);
assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo(
ServiceState.STATE_IN_SERVICE);
@@ -269,12 +277,10 @@
@Test
public void getCombinedServiceState_voiceOutOfServiceDataInService_returnInService() {
- when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
- when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+ when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
- AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo);
- when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn(
- NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN);
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).thenReturn(mNetworkRegistrationInfo);
+ when(mNetworkRegistrationInfo.isInService()).thenReturn(true);
assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo(
ServiceState.STATE_IN_SERVICE);
@@ -282,12 +288,10 @@
@Test
public void getCombinedServiceState_voiceOutOfServiceDataInServiceOnIwLan_returnOutOfService() {
- when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
- when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+ when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).thenReturn(mNetworkRegistrationInfo);
- when(mNetworkRegistrationInfo.getRegistrationState()).thenReturn(
- NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+ when(mNetworkRegistrationInfo.isInService()).thenReturn(true);
assertThat(Utils.getCombinedServiceState(mServiceState)).isEqualTo(
ServiceState.STATE_OUT_OF_SERVICE);
@@ -295,7 +299,7 @@
@Test
public void getCombinedServiceState_voiceOutOfServiceDataOutOfService_returnOutOfService() {
- when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+ when(mServiceState.getVoiceRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(
ServiceState.STATE_OUT_OF_SERVICE);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 000612b..77925d6 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -296,8 +296,6 @@
/* Biometric converted tests */
"tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt",
- "tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt",
- "tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt",
"tests/src/com/android/systemui/biometrics/AuthControllerTest.java",
"tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java",
"tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt",
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index a3a1fa5..0c07616 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -24,6 +24,7 @@
import android.graphics.Path
import android.graphics.Rect
import android.graphics.RectF
+import android.os.Build
import android.os.Looper
import android.os.RemoteException
import android.util.Log
@@ -88,6 +89,9 @@
contentAfterFadeInInterpolator = PathInterpolator(0f, 0f, 0.6f, 1f)
)
+ // TODO(b/288507023): Remove this flag.
+ @JvmField val DEBUG_LAUNCH_ANIMATION = Build.IS_DEBUGGABLE
+
private val DEFAULT_LAUNCH_ANIMATOR = LaunchAnimator(TIMINGS, INTERPOLATORS)
private val DEFAULT_DIALOG_TO_APP_ANIMATOR = LaunchAnimator(DIALOG_TIMINGS, INTERPOLATORS)
@@ -244,11 +248,13 @@
callOnIntentStartedOnMainThread(willAnimate)
}
} else {
- // TODO(b/288507023): Remove this log.
- Log.d(
- TAG,
- "Calling controller.onIntentStarted(willAnimate=$willAnimate) [controller=$this]"
- )
+ if (DEBUG_LAUNCH_ANIMATION) {
+ Log.d(
+ TAG,
+ "Calling controller.onIntentStarted(willAnimate=$willAnimate) " +
+ "[controller=$this]"
+ )
+ }
this.onIntentStarted(willAnimate)
}
}
@@ -549,8 +555,12 @@
removeTimeout()
iCallback?.invoke()
- // TODO(b/288507023): Remove this log.
- Log.d(TAG, "Calling controller.onLaunchAnimationCancelled() [no window opening]")
+ if (DEBUG_LAUNCH_ANIMATION) {
+ Log.d(
+ TAG,
+ "Calling controller.onLaunchAnimationCancelled() [no window opening]"
+ )
+ }
controller.onLaunchAnimationCancelled()
return
}
@@ -769,8 +779,9 @@
Log.i(TAG, "Remote animation timed out")
timedOut = true
- // TODO(b/288507023): Remove this log.
- Log.d(TAG, "Calling controller.onLaunchAnimationCancelled() [animation timed out]")
+ if (DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "Calling controller.onLaunchAnimationCancelled() [animation timed out]")
+ }
controller.onLaunchAnimationCancelled()
}
@@ -786,11 +797,12 @@
animation?.cancel()
- // TODO(b/288507023): Remove this log.
- Log.d(
- TAG,
- "Calling controller.onLaunchAnimationCancelled() [remote animation cancelled]",
- )
+ if (DEBUG_LAUNCH_ANIMATION) {
+ Log.d(
+ TAG,
+ "Calling controller.onLaunchAnimationCancelled() [remote animation cancelled]",
+ )
+ }
controller.onLaunchAnimationCancelled()
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index 81b9eb0..e06a69b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -55,6 +55,7 @@
import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
@@ -82,9 +83,10 @@
override val key = SceneKey.Bouncer
override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
- MutableStateFlow<Map<UserAction, SceneModel>>(
+ MutableStateFlow(
mapOf(
UserAction.Back to SceneModel(SceneKey.Lockscreen),
+ UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Lockscreen),
)
)
.asStateFlow()
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml
new file mode 100644
index 0000000..6835d59
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+**
+** Copyright 2023, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This file is needed when flag lockscreen.enable_landscape is on
+ Required for landscape lockscreen on small screens. -->
+<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/keyguard_pin_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal|bottom"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+
+ <!-- Layout here is visually identical to the previous keyguard_pin_view.
+ I.E., 'constraints here effectively the same as the previous linear layout '-->
+ <androidx.constraintlayout.motion.widget.MotionLayout
+ android:id="@+id/pin_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:layoutDirection="ltr"
+ android:orientation="vertical"
+ androidprv:layoutDescription="@xml/keyguard_pin_scene"
+ android:layout_gravity="center_horizontal">
+
+ <!-- Guideline need to align PIN pad left of centre,
+ when on small screen landscape layout -->
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/pin_pad_center_guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ androidprv:layout_constraintGuide_percent="0.5" />
+
+ <!-- Guideline used to place the top row of keys relative to the screen height. This will be
+ updated in KeyguardPINView to reduce the height of the PIN pad. -->
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/pin_pad_top_guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ androidprv:layout_constraintGuide_percent="0" />
+
+ <LinearLayout
+ android:id="@+id/keyguard_bouncer_message_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:layoutDirection="ltr"
+ android:orientation="vertical"
+ androidprv:layout_constraintTop_toTopOf="parent">
+
+ <include layout="@layout/keyguard_bouncer_message_area" />
+
+ <com.android.systemui.bouncer.ui.BouncerMessageView
+ android:id="@+id/bouncer_message_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" />
+
+ </LinearLayout>
+
+ <!-- Set this to be just above key1. It would be better to introduce a barrier above
+ key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier
+ drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any
+ case, the Flow should ensure that key1/2/3 all have the same top, so this should be
+ fine. -->
+ <com.android.keyguard.AlphaOptimizedRelativeLayout
+ android:id="@+id/row0"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
+ androidprv:layout_constraintBottom_toTopOf="@id/key1"
+ androidprv:layout_constraintEnd_toEndOf="parent"
+ androidprv:layout_constraintStart_toStartOf="parent"
+ androidprv:layout_constraintTop_toBottomOf="@id/keyguard_bouncer_message_container"
+ androidprv:layout_constraintVertical_bias="0.5">
+
+ <com.android.keyguard.PasswordTextView
+ android:id="@+id/pinEntry"
+ style="@style/Widget.TextView.Password"
+ android:layout_width="@dimen/keyguard_security_width"
+ android:layout_height="@dimen/keyguard_password_height"
+ android:layout_centerHorizontal="true"
+ android:layout_marginRight="72dp"
+ android:contentDescription="@string/keyguard_accessibility_pin_area"
+ androidprv:scaledTextSize="@integer/scaled_password_text_size" />
+
+ </com.android.keyguard.AlphaOptimizedRelativeLayout>
+
+ <com.android.keyguard.KeyguardPinFlowView
+ android:id="@+id/flow1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginBottom="8dp"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="horizontal"
+
+ androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
+
+ androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
+ androidprv:flow_horizontalStyle="packed"
+ androidprv:flow_maxElementsWrap="3"
+
+ androidprv:flow_verticalBias="1.0"
+ androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
+ androidprv:flow_verticalStyle="packed"
+ androidprv:flow_wrapMode="aligned"
+
+ androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container"
+ androidprv:layout_constraintEnd_toEndOf="parent"
+ androidprv:layout_constraintStart_toStartOf="parent"
+ androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" />
+
+ <com.android.keyguard.NumPadButton
+ android:id="@+id/delete_button"
+ style="@style/NumPadKey.Delete"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key0"
+ android:contentDescription="@string/keyboardview_keycode_delete" />
+
+ <com.android.keyguard.NumPadButton
+ android:id="@+id/key_enter"
+ style="@style/NumPadKey.Enter"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:contentDescription="@string/keyboardview_keycode_enter" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key2"
+ androidprv:digit="1"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key2"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key3"
+ androidprv:digit="2"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key3"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key4"
+ androidprv:digit="3"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key4"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key5"
+ androidprv:digit="4"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key5"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key6"
+ androidprv:digit="5"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key6"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key7"
+ androidprv:digit="6"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key7"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key8"
+ androidprv:digit="7"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key8"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key9"
+ androidprv:digit="8"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key9"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/delete_button"
+ androidprv:digit="9"
+ androidprv:textView="@+id/pinEntry" />
+
+ <com.android.keyguard.NumPadKey
+ android:id="@+id/key0"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:accessibilityTraversalBefore="@id/key_enter"
+ androidprv:digit="0"
+ androidprv:textView="@+id/pinEntry" />
+
+ <include
+ android:id="@+id/keyguard_selector_fade_container"
+ layout="@layout/keyguard_eca"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
+ android:layout_marginTop="@dimen/keyguard_eca_top_margin"
+ android:orientation="vertical"
+ androidprv:layout_constraintBottom_toBottomOf="parent"
+ androidprv:layout_constraintTop_toBottomOf="@+id/flow1" />
+
+ </androidx.constraintlayout.motion.widget.MotionLayout>
+
+</com.android.keyguard.KeyguardPINView>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-land/donottranslate.xml b/packages/SystemUI/res-keyguard/values-land/donottranslate.xml
deleted file mode 100644
index 9912b69..0000000
--- a/packages/SystemUI/res-keyguard/values-land/donottranslate.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 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.
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="num_pad_key_ratio">1.51</string>
-</resources>
diff --git a/packages/SystemUI/res-keyguard/xml/keyguard_pin_scene.xml b/packages/SystemUI/res-keyguard/xml/keyguard_pin_scene.xml
new file mode 100644
index 0000000..44af9ef
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/xml/keyguard_pin_scene.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2023, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<MotionScene
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:motion="http://schemas.android.com/apk/res-auto"
+ xmlns:androidprv="http://schemas.android.com/apk/res-auto">
+
+ <Transition
+ motion:constraintSetStart="@id/single_constraints"
+ motion:constraintSetEnd="@+id/split_constraints"
+ motion:duration="0"
+ motion:autoTransition="none">
+ </Transition>
+
+ <ConstraintSet android:id="@+id/single_constraints">
+ <!-- No changes to default layout -->
+ </ConstraintSet>
+
+ <ConstraintSet android:id="@+id/split_constraints">
+
+ <Constraint
+ android:id="@+id/keyguard_bouncer_message_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ androidprv:layout_constraintEnd_toStartOf="@+id/pin_pad_center_guideline"
+ androidprv:layout_constraintStart_toStartOf="parent"
+ androidprv:layout_constraintTop_toTopOf="parent" />
+ <Constraint
+ android:id="@+id/row0"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ androidprv:layout_constraintEnd_toStartOf="@+id/pin_pad_center_guideline"
+ androidprv:layout_constraintStart_toStartOf="parent"
+ androidprv:layout_constraintTop_toBottomOf="@+id/keyguard_bouncer_message_container" />
+ <Constraint
+ android:id="@+id/flow1"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:layout_constraintBottom_toBottomOf="parent"
+ androidprv:layout_constraintEnd_toEndOf="parent"
+ androidprv:layout_constraintStart_toStartOf="@+id/pin_pad_center_guideline"
+ androidprv:layout_constraintTop_toTopOf="parent"
+ android:layout_marginBottom="0dp"
+ androidprv:flow_verticalBias="0.5" />
+ <Constraint
+ android:id="@+id/keyguard_selector_fade_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ androidprv:layout_constraintBottom_toBottomOf="parent"
+ androidprv:layout_constraintEnd_toStartOf="@+id/pin_pad_center_guideline"
+ androidprv:layout_constraintStart_toStartOf="parent"
+ android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
+ android:layout_marginTop="@dimen/keyguard_eca_top_margin" />
+
+ </ConstraintSet>
+</MotionScene>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
deleted file mode 100644
index 50b3bec..0000000
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ /dev/null
@@ -1,165 +0,0 @@
-<!--
- ~ Copyright (C) 2019 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.
- -->
-<!-- TODO(b/251476085): inline in biometric_prompt_layout after Biometric*Views are un-flagged -->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:singleLine="true"
- android:marqueeRepeatLimit="1"
- android:ellipsize="marquee"
- android:importantForAccessibility="no"
- style="@style/TextAppearance.AuthCredential.Title"/>
-
- <TextView
- android:id="@+id/subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:singleLine="true"
- android:marqueeRepeatLimit="1"
- android:ellipsize="marquee"
- android:importantForAccessibility="no"
- style="@style/TextAppearance.AuthCredential.Subtitle"/>
-
- <TextView
- android:id="@+id/description"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scrollbars ="vertical"
- style="@style/TextAppearance.AuthCredential.Description"/>
-
- <Space android:id="@+id/space_above_icon"
- android:layout_width="match_parent"
- android:layout_height="48dp" />
-
- <FrameLayout
- android:id="@+id/biometric_icon_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center">
-
- <include layout="@layout/auth_biometric_icon"/>
-
- <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
- android:id="@+id/biometric_icon_overlay"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:contentDescription="@null"
- android:scaleType="fitXY" />
- </FrameLayout>
-
- <!-- For sensors such as UDFPS, this view is used during custom measurement/layout to add extra
- padding so that the biometric icon is always in the right physical position. -->
- <Space android:id="@+id/space_below_icon"
- android:layout_width="match_parent"
- android:layout_height="12dp" />
-
- <TextView
- android:id="@+id/indicator"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingHorizontal="24dp"
- android:textSize="12sp"
- android:gravity="center_horizontal"
- android:accessibilityLiveRegion="polite"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:scrollHorizontally="true"
- android:fadingEdge="horizontal"
- android:textColor="@color/biometric_dialog_gray"/>
-
- <LinearLayout
- android:id="@+id/button_bar"
- android:layout_width="match_parent"
- android:layout_height="88dp"
- style="?android:attr/buttonBarStyle"
- android:orientation="horizontal"
- android:paddingTop="24dp">
-
- <Space android:id="@+id/leftSpacer"
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:visibility="visible" />
-
- <!-- Negative Button, reserved for app -->
- <Button android:id="@+id/button_negative"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_gravity="center_vertical"
- android:ellipsize="end"
- android:maxLines="2"
- android:maxWidth="@dimen/biometric_dialog_button_negative_max_width"/>
- <!-- Cancel Button, replaces negative button when biometric is accepted -->
- <Button android:id="@+id/button_cancel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_gravity="center_vertical"
- android:maxWidth="@dimen/biometric_dialog_button_negative_max_width"
- android:text="@string/cancel"
- android:visibility="gone"/>
- <!-- "Use Credential" Button, replaces if device credential is allowed -->
- <Button android:id="@+id/button_use_credential"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_gravity="center_vertical"
- android:maxWidth="@dimen/biometric_dialog_button_negative_max_width"
- android:visibility="gone"/>
-
- <Space android:id="@+id/middleSpacer"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:visibility="visible"/>
-
- <!-- Positive Button -->
- <Button android:id="@+id/button_confirm"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:layout_gravity="center_vertical"
- android:ellipsize="end"
- android:maxLines="2"
- android:maxWidth="@dimen/biometric_dialog_button_positive_max_width"
- android:text="@string/biometric_dialog_confirm"
- android:visibility="gone"/>
- <!-- Try Again Button -->
- <Button android:id="@+id/button_try_again"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:layout_gravity="center_vertical"
- android:ellipsize="end"
- android:maxLines="2"
- android:maxWidth="@dimen/biometric_dialog_button_positive_max_width"
- android:text="@string/biometric_dialog_try_again"
- android:visibility="gone"/>
-
- <Space android:id="@+id/rightSpacer"
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:visibility="visible" />
- </LinearLayout>
-
-</merge>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_biometric_face_view.xml b/packages/SystemUI/res/layout/auth_biometric_face_view.xml
deleted file mode 100644
index e3d0732..0000000
--- a/packages/SystemUI/res/layout/auth_biometric_face_view.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- ~ Copyright (C) 2019 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.
- -->
-<!-- TODO(b/251476085): remove after BiometricFaceView is un-flagged -->
-<com.android.systemui.biometrics.AuthBiometricFaceView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/contents"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <include layout="@layout/auth_biometric_contents"/>
-
-</com.android.systemui.biometrics.AuthBiometricFaceView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_biometric_fingerprint_and_face_view.xml b/packages/SystemUI/res/layout/auth_biometric_fingerprint_and_face_view.xml
deleted file mode 100644
index 896d836..0000000
--- a/packages/SystemUI/res/layout/auth_biometric_fingerprint_and_face_view.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- ~ Copyright (C) 2021 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.
- -->
-<!-- TODO(b/251476085): remove after BiometricFingerprintAndFaceView is un-flagged -->
-<com.android.systemui.biometrics.AuthBiometricFingerprintAndFaceView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/contents"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <include layout="@layout/auth_biometric_contents"/>
-
-</com.android.systemui.biometrics.AuthBiometricFingerprintAndFaceView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_biometric_fingerprint_view.xml b/packages/SystemUI/res/layout/auth_biometric_fingerprint_view.xml
deleted file mode 100644
index e36f9796..0000000
--- a/packages/SystemUI/res/layout/auth_biometric_fingerprint_view.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- ~ Copyright (C) 2019 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.
- -->
-<!-- TODO(b/251476085): remove after BiometricFingerprintView is un-flagged -->
-<com.android.systemui.biometrics.AuthBiometricFingerprintView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/contents"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <include layout="@layout/auth_biometric_contents"/>
-
-</com.android.systemui.biometrics.AuthBiometricFingerprintView>
\ No newline at end of file
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index a6517c1..0415341 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -46,6 +46,7 @@
":wm_shell_util-sources",
],
static_libs: [
+ "BiometricsSharedLib",
"PluginCoreLib",
"SystemUIAnimationLib",
"SystemUIPluginLib",
diff --git a/packages/SystemUI/shared/biometrics/Android.bp b/packages/SystemUI/shared/biometrics/Android.bp
new file mode 100644
index 0000000..2bd7d97
--- /dev/null
+++ b/packages/SystemUI/shared/biometrics/Android.bp
@@ -0,0 +1,20 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+ name: "BiometricsSharedLib",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ resource_dirs: [
+ "res",
+ ],
+ min_sdk_version: "current",
+}
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp-land/donottranslate.xml b/packages/SystemUI/shared/biometrics/AndroidManifest.xml
similarity index 68%
rename from packages/SystemUI/res-keyguard/values-sw600dp-land/donottranslate.xml
rename to packages/SystemUI/shared/biometrics/AndroidManifest.xml
index 1a52e93..861321b 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp-land/donottranslate.xml
+++ b/packages/SystemUI/shared/biometrics/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2021 The Android Open Source Project
+ ~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
~ limitations under the License.
-->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use the smaller PIN pad keys if we have the screen space to support it. -->
- <string name="num_pad_key_ratio">1.0</string>
-</resources>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.shared.biometrics">
+</manifest>
\ No newline at end of file
diff --git a/packages/SystemUI/shared/biometrics/res/values/strings.xml b/packages/SystemUI/shared/biometrics/res/values/strings.xml
new file mode 100644
index 0000000..c15c2b3
--- /dev/null
+++ b/packages/SystemUI/shared/biometrics/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- [CHAR LIMIT=NONE] Messages shown when users press outside udfps region during -->
+ <string name="udfps_accessibility_touch_hints_left"> Move left </string>
+ <!-- [CHAR LIMIT=NONE] Messages shown when users press outside udfps region during -->
+ <string name="udfps_accessibility_touch_hints_down"> Move down </string>
+ <!-- [CHAR LIMIT=NONE] Messages shown when users press outside udfps region during -->
+ <string name="udfps_accessibility_touch_hints_right"> Move right </string>
+ <!-- [CHAR LIMIT=NONE] Messages shown when users press outside udfps region during -->
+ <string name="udfps_accessibility_touch_hints_up"> Move up </string>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsUtils.java b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/UdfpsUtils.java
similarity index 91%
rename from packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsUtils.java
rename to packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/UdfpsUtils.java
index 31f014c..9574fba 100644
--- a/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsUtils.java
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/UdfpsUtils.java
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.settingslib.udfps;
+package com.android.systemui.biometrics;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Point;
import android.util.DisplayUtils;
import android.util.Log;
@@ -26,7 +27,8 @@
import android.view.MotionEvent;
import android.view.Surface;
-import com.android.settingslib.R;
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
+import com.android.systemui.shared.biometrics.R;
/** Utility class for working with udfps. */
public class UdfpsUtils {
@@ -95,12 +97,13 @@
return null;
}
- String[] touchHints = context.getResources().getStringArray(
- R.array.udfps_accessibility_touch_hints);
- if (touchHints.length != 4) {
- Log.e(TAG, "expected exactly 4 touch hints, got " + touchHints.length + "?");
- return null;
- }
+ Resources resources = context.getResources();
+ String[] touchHints = new String[] {
+ resources.getString(R.string.udfps_accessibility_touch_hints_left),
+ resources.getString(R.string.udfps_accessibility_touch_hints_down),
+ resources.getString(R.string.udfps_accessibility_touch_hints_right),
+ resources.getString(R.string.udfps_accessibility_touch_hints_up),
+ };
// Scale the coordinates to native resolution.
float scale = udfpsOverlayParams.getScaleFactor();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/Utils.kt
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt
rename to packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/Utils.kt
index 1ca57e7..422f02f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/Utils.kt
@@ -47,12 +47,12 @@
const val CREDENTIAL_PATTERN = 2
const val CREDENTIAL_PASSWORD = 3
- /** Base set of layout flags for fingerprint overlay widgets. */
+ /** Base set of layout flags for fingerprint overlay widgets. */
const val FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS =
- (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
+ (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
+ WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
@JvmStatic
fun dpToPixels(context: Context, dp: Float): Float {
@@ -61,9 +61,8 @@
}
/**
- * Note: Talkback 14.0 has new rate-limitation design to reduce frequency
- * of TYPE_WINDOW_CONTENT_CHANGED events to once every 30 seconds.
- * (context: b/281765653#comment18)
+ * Note: Talkback 14.0 has new rate-limitation design to reduce frequency of
+ * TYPE_WINDOW_CONTENT_CHANGED events to once every 30 seconds. (context: b/281765653#comment18)
* Using {@link View#announceForAccessibility} instead as workaround when sending events
* exceeding this frequency is required.
*/
@@ -74,8 +73,7 @@
}
val event = AccessibilityEvent.obtain()
event.eventType = AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
- event.contentChangeTypes =
- AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE
+ event.contentChangeTypes = AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE
view.sendAccessibilityEventUnchecked(event)
view.notifySubtreeAccessibilityStateChanged(
view,
@@ -119,8 +117,8 @@
@JvmStatic
fun isSystem(context: Context, clientPackage: String?): Boolean {
val hasPermission =
- (context.checkCallingOrSelfPermission(Manifest.permission.USE_BIOMETRIC_INTERNAL)
- == PackageManager.PERMISSION_GRANTED)
+ (context.checkCallingOrSelfPermission(Manifest.permission.USE_BIOMETRIC_INTERNAL) ==
+ PackageManager.PERMISSION_GRANTED)
return hasPermission && "android" == clientPackage
}
@@ -134,5 +132,5 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef(CREDENTIAL_PIN, CREDENTIAL_PATTERN, CREDENTIAL_PASSWORD)
- internal annotation class CredentialType
-}
\ No newline at end of file
+ annotation class CredentialType
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricModalities.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricModalities.kt
rename to packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
index 274f58a..db46ccf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricModalities.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.biometrics.domain.model
+package com.android.systemui.biometrics.shared.model
import android.hardware.biometrics.SensorProperties
import android.hardware.face.FaceSensorPropertiesInternal
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/BiometricModality.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModality.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/biometrics/shared/model/BiometricModality.kt
rename to packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModality.kt
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/BiometricUserInfo.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricUserInfo.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/biometrics/shared/model/BiometricUserInfo.kt
rename to packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricUserInfo.kt
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
rename to packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
index c6fdcb3..6082fb9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
@@ -25,7 +25,7 @@
UDFPS_ULTRASONIC,
UDFPS_OPTICAL,
POWER_BUTTON,
- HOME_BUTTON,
+ HOME_BUTTON
}
/** Convert [this] to corresponding [FingerprintSensorType] */
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LockoutMode.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/LockoutMode.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LockoutMode.kt
rename to packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/LockoutMode.kt
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
rename to packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt
diff --git a/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsOverlayParams.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/UdfpsOverlayParams.kt
similarity index 96%
rename from packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsOverlayParams.kt
rename to packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/UdfpsOverlayParams.kt
index b386e5e..a9b4fe8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/udfps/UdfpsOverlayParams.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/UdfpsOverlayParams.kt
@@ -1,4 +1,4 @@
-package com.android.settingslib.udfps
+package com.android.systemui.biometrics.shared.model
import android.graphics.Rect
import android.view.Surface
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
index 77f6d03..eb20669 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
@@ -61,8 +61,6 @@
InteractionJankMonitor.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS;
public static final int CUJ_OPEN_SEARCH_RESULT =
InteractionJankMonitor.CUJ_LAUNCHER_OPEN_SEARCH_RESULT;
- public static final int CUJ_SHADE_EXPAND_FROM_STATUS_BAR =
- InteractionJankMonitor.CUJ_SHADE_EXPAND_FROM_STATUS_BAR;
@IntDef({
CUJ_APP_LAUNCH_FROM_RECENTS,
@@ -79,7 +77,6 @@
CUJ_CLOSE_ALL_APPS_SWIPE,
CUJ_CLOSE_ALL_APPS_TO_HOME,
CUJ_OPEN_SEARCH_RESULT,
- CUJ_SHADE_EXPAND_FROM_STATUS_BAR,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
index a72d813..98f082f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
@@ -64,8 +64,10 @@
return false;
}
- /** Change motion layout constraint set based on orientation */
- protected void updateConstraints(int orientation) {
+ /** Updates the keyguard view's constraints (single or split constraints).
+ * Split constraints are only used for small landscape screens.
+ * Only called when flag LANDSCAPE_ENABLE_LOCKSCREEN is enabled. */
+ protected void updateConstraints(boolean useSplitBouncer) {
//Unless overridden, never update constrains (keeping default portrait constraints)
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 42dbc48..8738d33 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -16,6 +16,8 @@
package com.android.keyguard;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
+
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -257,6 +259,8 @@
mFalsingCollector, mKeyguardViewController,
mFeatureFlags);
} else if (keyguardInputView instanceof KeyguardPINView) {
+ ((KeyguardPINView) keyguardInputView).setIsLockScreenLandscapeEnabled(
+ mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE));
return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index d9b7bde..bb3e759 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -16,12 +16,15 @@
package com.android.keyguard;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_APPEAR;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR;
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.util.AttributeSet;
@@ -30,6 +33,7 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import androidx.constraintlayout.motion.widget.MotionLayout;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
@@ -46,12 +50,15 @@
ValueAnimator mAppearAnimator = ValueAnimator.ofFloat(0f, 1f);
private final DisappearAnimationUtils mDisappearAnimationUtils;
private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
- private ConstraintLayout mContainer;
+ @Nullable private MotionLayout mContainerMotionLayout;
+ @Nullable private ConstraintLayout mContainerConstraintLayout;
private int mDisappearYTranslation;
private View[][] mViews;
private int mYTrans;
private int mYTransOffset;
private View mBouncerMessageArea;
+ private boolean mAlreadyUsingSplitBouncer = false;
+ private boolean mIsLockScreenLandscapeEnabled = false;
@DevicePostureInt private int mLastDevicePosture = DEVICE_POSTURE_UNKNOWN;
public static final long ANIMATION_DURATION = 650;
@@ -76,6 +83,22 @@
mYTransOffset = getResources().getDimensionPixelSize(R.dimen.pin_view_trans_y_entry_offset);
}
+ /** Use motion layout (new bouncer implementation) if LOCKSCREEN_ENABLE_LANDSCAPE flag is
+ * enabled, instead of constraint layout (old bouncer implementation) */
+ public void setIsLockScreenLandscapeEnabled(boolean isLockScreenLandscapeEnabled) {
+ mIsLockScreenLandscapeEnabled = isLockScreenLandscapeEnabled;
+ findContainerLayout();
+ }
+
+ private void findContainerLayout() {
+ if (mIsLockScreenLandscapeEnabled) {
+ mContainerMotionLayout = findViewById(R.id.pin_container);
+ } else {
+ mContainerConstraintLayout = findViewById(R.id.pin_container);
+ }
+ }
+
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
updateMargins();
@@ -84,6 +107,17 @@
void onDevicePostureChanged(@DevicePostureInt int posture) {
if (mLastDevicePosture != posture) {
mLastDevicePosture = posture;
+
+ if (mIsLockScreenLandscapeEnabled) {
+ boolean useSplitBouncerAfterFold =
+ mLastDevicePosture == DEVICE_POSTURE_CLOSED
+ && getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE;
+
+ if (mAlreadyUsingSplitBouncer != useSplitBouncerAfterFold) {
+ updateConstraints(useSplitBouncerAfterFold);
+ }
+ }
+
updateMargins();
}
}
@@ -135,18 +169,40 @@
float halfOpenPercentage =
mContext.getResources().getFloat(R.dimen.half_opened_bouncer_height_ratio);
- ConstraintSet cs = new ConstraintSet();
- cs.clone(mContainer);
- cs.setGuidelinePercent(R.id.pin_pad_top_guideline,
- mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
- cs.applyTo(mContainer);
+ if (mIsLockScreenLandscapeEnabled) {
+ ConstraintSet cs = mContainerMotionLayout.getConstraintSet(R.id.single_constraints);
+ cs.setGuidelinePercent(R.id.pin_pad_top_guideline,
+ mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
+ cs.applyTo(mContainerMotionLayout);
+ } else {
+ ConstraintSet cs = new ConstraintSet();
+ cs.clone(mContainerConstraintLayout);
+ cs.setGuidelinePercent(R.id.pin_pad_top_guideline,
+ mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
+ cs.applyTo(mContainerConstraintLayout);
+ }
+ }
+
+ /** Updates the keyguard view's constraints (single or split constraints).
+ * Split constraints are only used for small landscape screens.
+ * Only called when flag LANDSCAPE_ENABLE_LOCKSCREEN is enabled. */
+ @Override
+ protected void updateConstraints(boolean useSplitBouncer) {
+ mAlreadyUsingSplitBouncer = useSplitBouncer;
+ if (useSplitBouncer) {
+ mContainerMotionLayout.jumpToState(R.id.split_constraints);
+ mContainerMotionLayout.setMaxWidth(Integer.MAX_VALUE);
+ } else {
+ mContainerMotionLayout.jumpToState(R.id.single_constraints);
+ mContainerMotionLayout.setMaxWidth(getResources()
+ .getDimensionPixelSize(R.dimen.keyguard_security_width));
+ }
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mContainer = findViewById(R.id.pin_container);
mBouncerMessageArea = findViewById(R.id.bouncer_message_area);
mViews = new View[][]{
new View[]{
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index a2d8c50..e9dd08c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -17,7 +17,7 @@
package com.android.keyguard;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
-
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC;
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS;
import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_NONE_SECURITY;
@@ -74,6 +74,7 @@
import com.android.systemui.biometrics.SideFpsController;
import com.android.systemui.biometrics.SideFpsUiRequestSource;
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
@@ -94,6 +95,8 @@
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.GlobalSettings;
+import dagger.Lazy;
+
import java.io.File;
import java.util.Optional;
@@ -201,7 +204,6 @@
};
private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {
-
@Override
public void onUserInput() {
mBouncerMessageInteractor.onPrimaryBouncerUserInput();
@@ -297,21 +299,23 @@
*/
@Override
public void finish(int targetUserId) {
- // If there's a pending runnable because the user interacted with a widget
- // and we're leaving keyguard, then run it.
- boolean deferKeyguardDone = false;
- mWillRunDismissFromKeyguard = false;
- if (mDismissAction != null) {
- deferKeyguardDone = mDismissAction.onDismiss();
- mWillRunDismissFromKeyguard = mDismissAction.willRunAnimationOnKeyguard();
- mDismissAction = null;
- mCancelAction = null;
- }
- if (mViewMediatorCallback != null) {
- if (deferKeyguardDone) {
- mViewMediatorCallback.keyguardDonePending(targetUserId);
- } else {
- mViewMediatorCallback.keyguardDone(targetUserId);
+ if (!mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ // If there's a pending runnable because the user interacted with a widget
+ // and we're leaving keyguard, then run it.
+ boolean deferKeyguardDone = false;
+ mWillRunDismissFromKeyguard = false;
+ if (mDismissAction != null) {
+ deferKeyguardDone = mDismissAction.onDismiss();
+ mWillRunDismissFromKeyguard = mDismissAction.willRunAnimationOnKeyguard();
+ mDismissAction = null;
+ mCancelAction = null;
+ }
+ if (mViewMediatorCallback != null) {
+ if (deferKeyguardDone) {
+ mViewMediatorCallback.keyguardDonePending(targetUserId);
+ } else {
+ mViewMediatorCallback.keyguardDone(targetUserId);
+ }
}
}
@@ -326,7 +330,6 @@
}
};
-
private final SwipeListener mSwipeListener = new SwipeListener() {
@Override
public void onSwipeUp() {
@@ -373,7 +376,8 @@
public void onOrientationChanged(int orientation) {
if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)
&& getResources().getBoolean(R.bool.update_bouncer_constraints)) {
- mSecurityViewFlipperController.updateConstraints(orientation);
+ boolean useSplitBouncer = orientation == ORIENTATION_LANDSCAPE;
+ mSecurityViewFlipperController.updateConstraints(useSplitBouncer);
}
}
};
@@ -416,6 +420,7 @@
private final Provider<AuthenticationInteractor> mAuthenticationInteractor;
private final Provider<JavaAdapter> mJavaAdapter;
private final DeviceProvisionedController mDeviceProvisionedController;
+ private final Lazy<PrimaryBouncerInteractor> mPrimaryBouncerInteractor;
@Nullable private Job mSceneTransitionCollectionJob;
@Inject
@@ -448,6 +453,7 @@
DeviceProvisionedController deviceProvisionedController,
FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate,
KeyguardTransitionInteractor keyguardTransitionInteractor,
+ Lazy<PrimaryBouncerInteractor> primaryBouncerInteractor,
Provider<AuthenticationInteractor> authenticationInteractor
) {
super(view);
@@ -482,6 +488,7 @@
mJavaAdapter = javaAdapter;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mDeviceProvisionedController = deviceProvisionedController;
+ mPrimaryBouncerInteractor = primaryBouncerInteractor;
}
@Override
@@ -618,6 +625,9 @@
* @param action callback to be invoked when keyguard disappear animation completes.
*/
public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
+ if (mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ return;
+ }
if (mCancelAction != null) {
mCancelAction.run();
}
@@ -820,7 +830,6 @@
*/
public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
-
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
if (expectedSecurityMode != SecurityMode.Invalid
&& expectedSecurityMode != getCurrentSecurityMode()) {
@@ -829,8 +838,8 @@
return false;
}
+ boolean authenticatedWithPrimaryAuth = false;
boolean finish = false;
- boolean primaryAuth = false;
int eventSubtype = -1;
BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN;
if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
@@ -855,7 +864,7 @@
case Pattern:
case Password:
case PIN:
- primaryAuth = true;
+ authenticatedWithPrimaryAuth = true;
finish = true;
eventSubtype = BOUNCER_DISMISS_PASSWORD;
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD;
@@ -901,6 +910,17 @@
if (uiEvent != BouncerUiEvent.UNKNOWN) {
mUiEventLogger.log(uiEvent, getSessionId());
}
+
+ if (mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ if (authenticatedWithPrimaryAuth) {
+ mPrimaryBouncerInteractor.get()
+ .notifyKeyguardAuthenticatedPrimaryAuth(targetUserId);
+ } else if (finish) {
+ mPrimaryBouncerInteractor.get().notifyUserRequestedBouncerWhenAlreadyAuthenticated(
+ targetUserId);
+ }
+ }
+
if (finish) {
mKeyguardSecurityCallback.finish(targetUserId);
}
@@ -1058,12 +1078,15 @@
* one side).
*/
private boolean canUseOneHandedBouncer() {
- if (!(mCurrentSecurityMode == SecurityMode.Pattern
- || mCurrentSecurityMode == SecurityMode.PIN)) {
- return false;
+ switch(mCurrentSecurityMode) {
+ case PIN:
+ case Pattern:
+ case SimPin:
+ case SimPuk:
+ return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
+ default:
+ return false;
}
-
- return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
}
private boolean canDisplayUserSwitcher() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
index 891eb14..74f9006 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
@@ -83,11 +83,13 @@
return "";
}
- /** Updates the keyguard view's constraints based on orientation */
- public void updateConstraints(int orientation) {
+ /** Updates the keyguard view's constraints (single or split constraints).
+ * Split constraints are only used for small landscape screens.
+ * Only called when flag LANDSCAPE_ENABLE_LOCKSCREEN is enabled. */
+ public void updateConstraints(boolean useSplitBouncer) {
KeyguardInputView securityView = getSecurityView();
if (securityView != null) {
- securityView.updateConstraints(orientation);
+ securityView.updateConstraints(useSplitBouncer);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index 74f0beb..4cc90c2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
import android.util.Log;
@@ -136,12 +137,14 @@
if (onViewInflatedListener != null) {
onViewInflatedListener.onViewInflated(childController);
- // Portrait constrains are default
+ // Single bouncer constrains are default
if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)
&&
getResources().getBoolean(R.bool.update_bouncer_constraints)) {
- // updateConstraints based on orientation (only on small screens)
- updateConstraints(getResources().getConfiguration().orientation);
+ boolean useSplitBouncer =
+ getResources().getConfiguration().orientation
+ == ORIENTATION_LANDSCAPE;
+ updateConstraints(useSplitBouncer);
}
}
});
@@ -152,7 +155,7 @@
// TODO (b/297863911, b/297864907) - implement motion layout for other bouncers
switch (securityMode) {
case Pattern: return R.layout.keyguard_pattern_view;
- case PIN: return R.layout.keyguard_pin_view;
+ case PIN: return R.layout.keyguard_pin_motion_layout;
case Password: return R.layout.keyguard_password_view;
case SimPin: return R.layout.keyguard_sim_pin_view;
case SimPuk: return R.layout.keyguard_sim_puk_view;
@@ -173,9 +176,11 @@
}
}
- /** Updates the keyguard view's constraints based on orientation */
- public void updateConstraints(int orientation) {
- mView.updateConstraints(orientation);
+ /** Updates the keyguard view's constraints (single or split constraints).
+ * Split constraints are only used for small landscape screens.
+ * Only called when flag LANDSCAPE_ENABLE_LOCKSCREEN is enabled. */
+ public void updateConstraints(boolean useSplitBouncer) {
+ mView.updateConstraints(useSplitBouncer);
}
/** Makes the supplied child visible if it is contained win this view, */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 886a1b5..1fc88ab 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -141,10 +141,10 @@
// GSM 02.17 version 5.0.1, Section 5.6 PIN Management
if ((entry.length() < 4) || (entry.length() > 8)) {
// otherwise, display a message to the user, and don't submit.
- mMessageAreaController.setMessage(
- com.android.systemui.R.string.kg_invalid_sim_pin_hint);
mView.resetPasswordText(true /* animate */, true /* announce */);
getKeyguardSecurityCallback().userActivity();
+ mMessageAreaController.setMessage(
+ com.android.systemui.R.string.kg_invalid_sim_pin_hint);
return;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index ab9b647..4649091 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -18,7 +18,6 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
-
import static com.android.keyguard.LockIconView.ICON_FINGERPRINT;
import static com.android.keyguard.LockIconView.ICON_LOCK;
import static com.android.keyguard.LockIconView.ICON_UNLOCK;
@@ -54,12 +53,12 @@
import androidx.annotation.VisibleForTesting;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-import com.android.settingslib.udfps.UdfpsOverlayParams;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.biometrics.UdfpsController;
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index 03ad132..7a8161e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -17,7 +17,6 @@
package com.android.systemui.accessibility;
import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_ACCESSIBILITY_ACTIONS;
-
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
import android.accessibilityservice.AccessibilityService;
@@ -57,8 +56,8 @@
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.Assert;
import dagger.Lazy;
@@ -186,8 +185,8 @@
private final DisplayTracker mDisplayTracker;
private Locale mLocale;
private final AccessibilityManager mA11yManager;
- private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
private final NotificationShadeWindowController mNotificationShadeController;
+ private final KeyguardStateController mKeyguardStateController;
private final ShadeController mShadeController;
private final Lazy<ShadeViewController> mShadeViewController;
private final StatusBarWindowCallback mNotificationShadeCallback;
@@ -197,13 +196,14 @@
public SystemActions(Context context,
UserTracker userTracker,
NotificationShadeWindowController notificationShadeController,
+ KeyguardStateController keyguardStateController,
ShadeController shadeController,
Lazy<ShadeViewController> shadeViewController,
- Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
Optional<Recents> recentsOptional,
DisplayTracker displayTracker) {
mContext = context;
mUserTracker = userTracker;
+ mKeyguardStateController = keyguardStateController;
mShadeController = shadeController;
mShadeViewController = shadeViewController;
mRecentsOptional = recentsOptional;
@@ -219,7 +219,6 @@
(keyguardShowing, keyguardOccluded, keyguardGoingAway, bouncerShowing, mDozing,
panelExpanded, isDreaming) ->
registerOrUnregisterDismissNotificationShadeAction();
- mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
}
@Override
@@ -307,8 +306,8 @@
mA11yManager.registerSystemAction(actionBack, SYSTEM_ACTION_ID_BACK);
mA11yManager.registerSystemAction(actionHome, SYSTEM_ACTION_ID_HOME);
mA11yManager.registerSystemAction(actionRecents, SYSTEM_ACTION_ID_RECENTS);
- if (mCentralSurfacesOptionalLazy.get().isPresent()) {
- // These two actions require the CentralSurfaces instance.
+ if (mShadeController.isShadeEnabled()) {
+ // These two actions require the shade to be enabled.
mA11yManager.registerSystemAction(actionNotifications, SYSTEM_ACTION_ID_NOTIFICATIONS);
mA11yManager.registerSystemAction(actionQuickSettings, SYSTEM_ACTION_ID_QUICK_SETTINGS);
}
@@ -329,13 +328,8 @@
private void registerOrUnregisterDismissNotificationShadeAction() {
Assert.isMainThread();
- // Saving state in instance variable since this callback is called quite often to avoid
- // binder calls
- final Optional<CentralSurfaces> centralSurfacesOptional =
- mCentralSurfacesOptionalLazy.get();
- if (centralSurfacesOptional.isPresent()
- && mShadeViewController.get().isPanelExpanded()
- && !centralSurfacesOptional.get().isKeyguardShowing()) {
+ if (mShadeViewController.get().isPanelExpanded()
+ && !mKeyguardStateController.isShowing()) {
if (!mDismissNotificationShadeActionRegistered) {
mA11yManager.registerSystemAction(
createRemoteAction(
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index 8d1fc5d..b2433d4 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -109,6 +109,9 @@
*/
val authenticationMethod: Flow<AuthenticationMethodModel>
+ /** The minimal length of a pattern. */
+ val minPatternLength: Int
+
/**
* Returns the currently-configured authentication method. This determines how the
* authentication challenge needs to be completed in order to unlock an otherwise locked device.
@@ -227,6 +230,8 @@
}
}
+ override val minPatternLength: Int = LockPatternUtils.MIN_LOCK_PATTERN_SIZE
+
override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
return withContext(backgroundDispatcher) {
blockingAuthenticationMethodInternal(userRepository.selectedUserId)
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index ecd7bae..57a4224 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -185,6 +185,9 @@
/** Whether the pattern should be visible for the currently-selected user. */
val isPatternVisible: StateFlow<Boolean> = repository.isPatternVisible
+ /** The minimal length of a pattern. */
+ val minPatternLength: Int = repository.minPatternLength
+
private var throttlingCountdownJob: Job? = null
init {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
index 0c7d56f..ea8f5d3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
@@ -20,14 +20,7 @@
import android.util.Log
import com.airbnb.lottie.LottieAnimationView
import com.android.systemui.R
-import com.android.systemui.biometrics.AuthBiometricView.BiometricState
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATING
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATING_ANIMATING_IN
-import com.android.systemui.biometrics.AuthBiometricView.STATE_ERROR
-import com.android.systemui.biometrics.AuthBiometricView.STATE_HELP
-import com.android.systemui.biometrics.AuthBiometricView.STATE_IDLE
-import com.android.systemui.biometrics.AuthBiometricView.STATE_PENDING_CONFIRMATION
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
private const val TAG = "AuthBiometricFaceIconController"
@@ -40,8 +33,7 @@
// false = dark to light, true = light to dark
private var lastPulseLightToDark = false
- @BiometricState
- private var state = 0
+ private var state: BiometricState = BiometricState.STATE_IDLE
init {
val size = context.resources.getDimensionPixelSize(R.dimen.biometric_dialog_face_icon_size)
@@ -66,54 +58,54 @@
}
override fun handleAnimationEnd(drawable: Drawable) {
- if (state == STATE_AUTHENTICATING || state == STATE_HELP) {
+ if (state == BiometricState.STATE_AUTHENTICATING || state == BiometricState.STATE_HELP) {
pulseInNextDirection()
}
}
- override fun updateIcon(@BiometricState oldState: Int, @BiometricState newState: Int) {
- val lastStateIsErrorIcon = (oldState == STATE_ERROR || oldState == STATE_HELP)
- if (newState == STATE_AUTHENTICATING_ANIMATING_IN) {
+ override fun updateIcon(oldState: BiometricState, newState: BiometricState) {
+ val lastStateIsErrorIcon = (oldState == BiometricState.STATE_ERROR || oldState == BiometricState.STATE_HELP)
+ if (newState == BiometricState.STATE_AUTHENTICATING_ANIMATING_IN) {
showStaticDrawable(R.drawable.face_dialog_pulse_dark_to_light)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_authenticating
)
- } else if (newState == STATE_AUTHENTICATING) {
+ } else if (newState == BiometricState.STATE_AUTHENTICATING) {
startPulsing()
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_authenticating
)
- } else if (oldState == STATE_PENDING_CONFIRMATION && newState == STATE_AUTHENTICATED) {
+ } else if (oldState == BiometricState.STATE_PENDING_CONFIRMATION && newState == BiometricState.STATE_AUTHENTICATED) {
animateIconOnce(R.drawable.face_dialog_dark_to_checkmark)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_confirmed
)
- } else if (lastStateIsErrorIcon && newState == STATE_IDLE) {
+ } else if (lastStateIsErrorIcon && newState == BiometricState.STATE_IDLE) {
animateIconOnce(R.drawable.face_dialog_error_to_idle)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_idle
)
- } else if (lastStateIsErrorIcon && newState == STATE_AUTHENTICATED) {
+ } else if (lastStateIsErrorIcon && newState == BiometricState.STATE_AUTHENTICATED) {
animateIconOnce(R.drawable.face_dialog_dark_to_checkmark)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_authenticated
)
- } else if (newState == STATE_ERROR && oldState != STATE_ERROR) {
+ } else if (newState == BiometricState.STATE_ERROR && oldState != BiometricState.STATE_ERROR) {
animateIconOnce(R.drawable.face_dialog_dark_to_error)
iconView.contentDescription = context.getString(
R.string.keyguard_face_failed
)
- } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
+ } else if (oldState == BiometricState.STATE_AUTHENTICATING && newState == BiometricState.STATE_AUTHENTICATED) {
animateIconOnce(R.drawable.face_dialog_dark_to_checkmark)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_authenticated
)
- } else if (newState == STATE_PENDING_CONFIRMATION) {
+ } else if (newState == BiometricState.STATE_PENDING_CONFIRMATION) {
animateIconOnce(R.drawable.face_dialog_wink_from_dark)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_authenticated
)
- } else if (newState == STATE_IDLE) {
+ } else if (newState == BiometricState.STATE_IDLE) {
showStaticDrawable(R.drawable.face_dialog_idle_static)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_idle
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.kt
deleted file mode 100644
index be89d10..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2019 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.biometrics
-
-import android.content.Context
-import android.hardware.biometrics.BiometricAuthenticator.Modality
-import android.util.AttributeSet
-
-/** Face only view for BiometricPrompt. */
-class AuthBiometricFaceView(
- context: Context,
- attrs: AttributeSet? = null
-) : AuthBiometricView(context, attrs) {
-
- override fun getDelayAfterAuthenticatedDurationMs() = HIDE_DELAY_MS
-
- override fun getStateForAfterError() = STATE_IDLE
-
- override fun handleResetAfterError() = resetErrorView()
-
- override fun handleResetAfterHelp() = resetErrorView()
-
- override fun supportsSmallDialog() = true
-
- override fun supportsManualRetry() = true
-
- override fun supportsRequireConfirmation() = true
-
- override fun createIconController(): AuthIconController =
- AuthBiometricFaceIconController(mContext, mIconView)
-
- override fun updateState(@BiometricState newState: Int) {
- if (newState == STATE_AUTHENTICATING_ANIMATING_IN ||
- newState == STATE_AUTHENTICATING && size == AuthDialog.SIZE_MEDIUM) {
- resetErrorView()
- }
-
- // Do this last since the state variable gets updated.
- super.updateState(newState)
- }
-
- override fun onAuthenticationFailed(
- @Modality modality: Int,
- failureReason: String?
- ) {
- if (size == AuthDialog.SIZE_MEDIUM) {
- if (supportsManualRetry()) {
- mTryAgainButton.visibility = VISIBLE
- mConfirmButton.visibility = GONE
- }
- }
-
- // Do this last since we want to know if the button is being animated (in the case of
- // small -> medium dialog)
- super.onAuthenticationFailed(modality, failureReason)
- }
-
- private fun resetErrorView() {
- mIndicatorView.setTextColor(mTextColorHint)
- mIndicatorView.visibility = INVISIBLE
- }
-
- companion object {
- /** Delay before dismissing after being authenticated/confirmed. */
- const val HIDE_DELAY_MS = 500
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
index 95610ae..fb22c6b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
@@ -20,11 +20,11 @@
import android.content.Context
import com.airbnb.lottie.LottieAnimationView
import com.android.systemui.R
-import com.android.systemui.biometrics.AuthBiometricView.BiometricState
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
-import com.android.systemui.biometrics.AuthBiometricView.STATE_ERROR
-import com.android.systemui.biometrics.AuthBiometricView.STATE_HELP
-import com.android.systemui.biometrics.AuthBiometricView.STATE_PENDING_CONFIRMATION
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_AUTHENTICATED
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_ERROR
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_HELP
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_PENDING_CONFIRMATION
/** Face/Fingerprint combined icon animator for BiometricPrompt. */
open class AuthBiometricFingerprintAndFaceIconController(
@@ -36,8 +36,8 @@
override val actsAsConfirmButton: Boolean = true
override fun shouldAnimateIconViewForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
): Boolean = when (newState) {
STATE_PENDING_CONFIRMATION -> true
else -> super.shouldAnimateIconViewForTransition(oldState, newState)
@@ -45,8 +45,8 @@
@RawRes
override fun getAnimationForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
): Int? = when (newState) {
STATE_AUTHENTICATED -> {
if (oldState == STATE_PENDING_CONFIRMATION) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
deleted file mode 100644
index 7ce74db..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
+++ /dev/null
@@ -1,58 +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.biometrics
-
-import android.content.Context
-import android.hardware.biometrics.BiometricAuthenticator.Modality
-import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
-import android.hardware.biometrics.BiometricConstants
-import android.hardware.face.FaceManager
-import android.util.AttributeSet
-import com.android.systemui.R
-
-/** Face/Fingerprint combined view for BiometricPrompt. */
-class AuthBiometricFingerprintAndFaceView(
- context: Context,
- attrs: AttributeSet?
-) : AuthBiometricFingerprintView(context, attrs) {
- var isFaceClass3 = false
-
- constructor (context: Context) : this(context, null)
-
- override fun getConfirmationPrompt() = R.string.biometric_dialog_tap_confirm_with_face
-
- override fun forceRequireConfirmation(@Modality modality: Int) = modality == TYPE_FACE
-
- override fun ignoreUnsuccessfulEventsFrom(@Modality modality: Int, unsuccessfulReason: String) =
- modality == TYPE_FACE && !(isFaceClass3 && isLockoutErrorString(unsuccessfulReason))
-
- override fun createIconController(): AuthIconController =
- AuthBiometricFingerprintAndFaceIconController(mContext, mIconView, mIconViewOverlay)
-
- override fun isCoex() = true
-
- private fun isLockoutErrorString(unsuccessfulReason: String) =
- unsuccessfulReason == FaceManager.getErrorString(
- mContext,
- BiometricConstants.BIOMETRIC_ERROR_LOCKOUT,
- 0 /*vendorCode */
- ) || unsuccessfulReason == FaceManager.getErrorString(
- mContext,
- BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
- 0 /*vendorCode */
- )
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index d82f458..683541b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -27,14 +27,15 @@
import com.airbnb.lottie.LottieAnimationView
import com.android.settingslib.widget.LottieColorUtils
import com.android.systemui.R
-import com.android.systemui.biometrics.AuthBiometricView.BiometricState
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATING
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATING_ANIMATING_IN
-import com.android.systemui.biometrics.AuthBiometricView.STATE_ERROR
-import com.android.systemui.biometrics.AuthBiometricView.STATE_HELP
-import com.android.systemui.biometrics.AuthBiometricView.STATE_IDLE
-import com.android.systemui.biometrics.AuthBiometricView.STATE_PENDING_CONFIRMATION
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_AUTHENTICATED
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_AUTHENTICATING
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_AUTHENTICATING_ANIMATING_IN
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_ERROR
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_HELP
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_IDLE
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_PENDING_CONFIRMATION
+
/** Fingerprint only icon animator for BiometricPrompt. */
open class AuthBiometricFingerprintIconController(
@@ -76,7 +77,7 @@
}
}
- private fun updateIconSideFps(@BiometricState lastState: Int, @BiometricState newState: Int) {
+ private fun updateIconSideFps(lastState: BiometricState, newState: BiometricState) {
val displayInfo = DisplayInfo()
context.display?.getDisplayInfo(displayInfo)
val rotation = getRotationFromDefault(displayInfo.rotation)
@@ -106,7 +107,7 @@
LottieColorUtils.applyDynamicColors(context, iconViewOverlay)
}
- private fun updateIconNormal(@BiometricState lastState: Int, @BiometricState newState: Int) {
+ private fun updateIconNormal(lastState: BiometricState, newState: BiometricState) {
val icon = getAnimationForTransition(lastState, newState) ?: return
if (!(lastState == STATE_AUTHENTICATING_ANIMATING_IN && newState == STATE_AUTHENTICATING)) {
@@ -125,7 +126,7 @@
LottieColorUtils.applyDynamicColors(context, iconView)
}
- override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
+ override fun updateIcon(lastState: BiometricState, newState: BiometricState) {
if (isSideFps) {
updateIconSideFps(lastState, newState)
} else {
@@ -135,7 +136,7 @@
}
@VisibleForTesting
- fun getIconContentDescription(@BiometricState newState: Int): CharSequence? {
+ fun getIconContentDescription(newState: BiometricState): CharSequence? {
val id = when (newState) {
STATE_IDLE,
STATE_AUTHENTICATING_ANIMATING_IN,
@@ -160,8 +161,8 @@
}
protected open fun shouldAnimateIconViewForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
) = when (newState) {
STATE_HELP,
STATE_ERROR -> true
@@ -172,8 +173,8 @@
}
private fun shouldAnimateSfpsIconViewForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
) = when (newState) {
STATE_HELP,
STATE_ERROR -> true
@@ -185,8 +186,8 @@
}
protected open fun shouldAnimateIconViewOverlayForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
) = when (newState) {
STATE_HELP,
STATE_ERROR -> true
@@ -198,8 +199,8 @@
@RawRes
protected open fun getAnimationForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
): Int? {
val id = when (newState) {
STATE_HELP,
@@ -231,8 +232,8 @@
@RawRes
private fun getSideFpsOverlayAnimationForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int,
+ oldState: BiometricState,
+ newState: BiometricState,
rotation: Int
): Int? = when (newState) {
STATE_HELP,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
deleted file mode 100644
index f2e4701..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2019 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.biometrics
-
-import android.content.Context
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
-import android.util.AttributeSet
-import android.util.Log
-import android.widget.FrameLayout
-import android.widget.TextView
-import com.android.systemui.R
-import com.android.systemui.biometrics.AuthController.ScaleFactorProvider
-
-private const val TAG = "AuthBiometricFingerprintView"
-
-/** Fingerprint only view for BiometricPrompt. */
-open class AuthBiometricFingerprintView(
- context: Context,
- attrs: AttributeSet? = null
-) : AuthBiometricView(context, attrs) {
- /** If this view is for a SFPS sensor. */
- var isSfps = false
- private set
-
- /** If this view is for a UDFPS sensor. */
- var isUdfps = false
- private set
-
- private var udfpsAdapter: UdfpsDialogMeasureAdapter? = null
- private var scaleFactorProvider: ScaleFactorProvider? = null
-
- /** Set the [sensorProps] of this sensor so the view can be customized prior to layout. */
- fun setSensorProperties(sensorProps: FingerprintSensorPropertiesInternal) {
- isSfps = sensorProps.isAnySidefpsType
- isUdfps = sensorProps.isAnyUdfpsType
- udfpsAdapter = if (isUdfps) UdfpsDialogMeasureAdapter(this, sensorProps) else null
- }
-
- fun setScaleFactorProvider(scaleProvider: ScaleFactorProvider?) {
- scaleFactorProvider = scaleProvider
- }
-
- override fun onMeasureInternal(width: Int, height: Int): AuthDialog.LayoutParams {
- val layoutParams = super.onMeasureInternal(width, height)
- val scale = scaleFactorProvider?.provide() ?: 1.0f
- return udfpsAdapter?.onMeasureInternal(width, height, layoutParams,
- scale) ?: layoutParams
- }
-
- override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
- super.onLayout(changed, left, top, right, bottom)
-
- val adapter = udfpsAdapter
- if (adapter != null) {
- // Move the UDFPS icon and indicator text if necessary. This probably only needs to happen
- // for devices where the UDFPS sensor is too low.
- // TODO(b/201510778): Update this logic to support cases where the sensor or text overlap
- // the button bar area.
- val bottomSpacerHeight = adapter.bottomSpacerHeight
- Log.w(TAG, "bottomSpacerHeight: $bottomSpacerHeight")
- if (bottomSpacerHeight < 0) {
- val iconFrame = findViewById<FrameLayout>(R.id.biometric_icon_frame)!!
- iconFrame.translationY = -bottomSpacerHeight.toFloat()
- val indicator = findViewById<TextView>(R.id.indicator)!!
- indicator.translationY = -bottomSpacerHeight.toFloat()
- }
- }
- }
-
- override fun getDelayAfterAuthenticatedDurationMs() = 500
-
- override fun getStateForAfterError() = STATE_AUTHENTICATING
-
- override fun handleResetAfterError() = showTouchSensorString()
-
- override fun handleResetAfterHelp() = showTouchSensorString()
-
- override fun supportsSmallDialog() = false
-
- override fun createIconController(): AuthIconController =
- AuthBiometricFingerprintIconController(mContext, mIconView, mIconViewOverlay)
-
- fun updateOverrideIconLayoutParamsSize() {
- udfpsAdapter?.let {
- val sensorDiameter = it.getSensorDiameter(scaleFactorProvider?.provide() ?: 1.0f)
- (mIconController as? AuthBiometricFingerprintIconController)?.iconLayoutParamSize =
- Pair(sensorDiameter, sensorDiameter)
- }
- }
-
- override fun onAttachedToWindow() {
- super.onAttachedToWindow()
- showTouchSensorString()
- }
-
- private fun showTouchSensorString() {
- mIndicatorView.setText(R.string.fingerprint_dialog_touch_sensor)
- mIndicatorView.setTextColor(mTextColorHint)
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
deleted file mode 100644
index ed4b91c..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ /dev/null
@@ -1,984 +0,0 @@
-/*
- * Copyright (C) 2019 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.biometrics;
-
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringRes;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Insets;
-import android.hardware.biometrics.BiometricAuthenticator.Modality;
-import android.hardware.biometrics.BiometricPrompt;
-import android.hardware.biometrics.PromptInfo;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.text.TextUtils;
-import android.text.method.ScrollingMovementMethod;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.R;
-
-import com.airbnb.lottie.LottieAnimationView;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Contains the Biometric views (title, subtitle, icon, buttons, etc.) and its controllers.
- */
-public abstract class AuthBiometricView extends LinearLayout implements AuthBiometricViewAdapter {
-
- private static final String TAG = "AuthBiometricView";
-
- /**
- * Authentication hardware idle.
- */
- public static final int STATE_IDLE = 0;
- /**
- * UI animating in, authentication hardware active.
- */
- public static final int STATE_AUTHENTICATING_ANIMATING_IN = 1;
- /**
- * UI animated in, authentication hardware active.
- */
- public static final int STATE_AUTHENTICATING = 2;
- /**
- * UI animated in, authentication hardware active.
- */
- public static final int STATE_HELP = 3;
- /**
- * Hard error, e.g. ERROR_TIMEOUT. Authentication hardware idle.
- */
- public static final int STATE_ERROR = 4;
- /**
- * Authenticated, waiting for user confirmation. Authentication hardware idle.
- */
- public static final int STATE_PENDING_CONFIRMATION = 5;
- /**
- * Authenticated, dialog animating away soon.
- */
- public static final int STATE_AUTHENTICATED = 6;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({STATE_IDLE, STATE_AUTHENTICATING_ANIMATING_IN, STATE_AUTHENTICATING, STATE_HELP,
- STATE_ERROR, STATE_PENDING_CONFIRMATION, STATE_AUTHENTICATED})
- @interface BiometricState {}
-
- /**
- * Callback to the parent when a user action has occurred.
- */
- public interface Callback {
- int ACTION_AUTHENTICATED = 1;
- int ACTION_USER_CANCELED = 2;
- int ACTION_BUTTON_NEGATIVE = 3;
- int ACTION_BUTTON_TRY_AGAIN = 4;
- int ACTION_ERROR = 5;
- int ACTION_USE_DEVICE_CREDENTIAL = 6;
- int ACTION_START_DELAYED_FINGERPRINT_SENSOR = 7;
- int ACTION_AUTHENTICATED_AND_CONFIRMED = 8;
-
- /**
- * When an action has occurred. The caller will only invoke this when the callback should
- * be propagated. e.g. the caller will handle any necessary delay.
- * @param action
- */
- void onAction(int action);
- }
-
- private final Handler mHandler;
- private final AccessibilityManager mAccessibilityManager;
- private final LockPatternUtils mLockPatternUtils;
- protected final int mTextColorError;
- protected final int mTextColorHint;
-
- private AuthPanelController mPanelController;
-
- private PromptInfo mPromptInfo;
- private boolean mRequireConfirmation;
- private int mUserId;
- private int mEffectiveUserId;
- private @AuthDialog.DialogSize int mSize = AuthDialog.SIZE_UNKNOWN;
-
- private TextView mTitleView;
- private TextView mSubtitleView;
- private TextView mDescriptionView;
- private View mIconHolderView;
- protected LottieAnimationView mIconViewOverlay;
- protected LottieAnimationView mIconView;
- protected TextView mIndicatorView;
-
- @VisibleForTesting @NonNull AuthIconController mIconController;
- @VisibleForTesting int mAnimationDurationShort = AuthDialog.ANIMATE_SMALL_TO_MEDIUM_DURATION_MS;
- @VisibleForTesting int mAnimationDurationLong = AuthDialog.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS;
- @VisibleForTesting int mAnimationDurationHideDialog = BiometricPrompt.HIDE_DIALOG_DELAY;
-
- // Negative button position, exclusively for the app-specified behavior
- @VisibleForTesting Button mNegativeButton;
- // Negative button position, exclusively for cancelling auth after passive auth success
- @VisibleForTesting Button mCancelButton;
- // Negative button position, shown if device credentials are allowed
- @VisibleForTesting Button mUseCredentialButton;
-
- // Positive button position,
- @VisibleForTesting Button mConfirmButton;
- @VisibleForTesting Button mTryAgainButton;
-
- // Measurements when biometric view is showing text, buttons, etc.
- @Nullable @VisibleForTesting AuthDialog.LayoutParams mLayoutParams;
-
- private Callback mCallback;
- @BiometricState private int mState;
-
- private float mIconOriginalY;
-
- protected boolean mDialogSizeAnimating;
- protected Bundle mSavedState;
-
- private final Runnable mResetErrorRunnable;
- private final Runnable mResetHelpRunnable;
-
- private Animator.AnimatorListener mJankListener;
-
- private final boolean mUseCustomBpSize;
- private final int mCustomBpWidth;
- private final int mCustomBpHeight;
-
- private final OnClickListener mBackgroundClickListener = (view) -> {
- if (mState == STATE_AUTHENTICATED) {
- Log.w(TAG, "Ignoring background click after authenticated");
- return;
- } else if (mSize == AuthDialog.SIZE_SMALL) {
- Log.w(TAG, "Ignoring background click during small dialog");
- return;
- } else if (mSize == AuthDialog.SIZE_LARGE) {
- Log.w(TAG, "Ignoring background click during large dialog");
- return;
- }
- mCallback.onAction(Callback.ACTION_USER_CANCELED);
- };
-
- public AuthBiometricView(Context context) {
- this(context, null);
- }
-
- public AuthBiometricView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mHandler = new Handler(Looper.getMainLooper());
- mTextColorError = getResources().getColor(
- R.color.biometric_dialog_error, context.getTheme());
- mTextColorHint = getResources().getColor(
- R.color.biometric_dialog_gray, context.getTheme());
-
- mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
- mLockPatternUtils = new LockPatternUtils(context);
-
- mResetErrorRunnable = () -> {
- updateState(getStateForAfterError());
- handleResetAfterError();
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- };
-
- mResetHelpRunnable = () -> {
- updateState(STATE_AUTHENTICATING);
- handleResetAfterHelp();
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- };
-
- mUseCustomBpSize = getResources().getBoolean(R.bool.use_custom_bp_size);
- mCustomBpWidth = getResources().getDimensionPixelSize(R.dimen.biometric_dialog_width);
- mCustomBpHeight = getResources().getDimensionPixelSize(R.dimen.biometric_dialog_height);
- }
-
- /** Delay after authentication is confirmed, before the dialog should be animated away. */
- protected int getDelayAfterAuthenticatedDurationMs() {
- return 0;
- }
-
- /** State that the dialog/icon should be in after showing a help message. */
- protected int getStateForAfterError() {
- return STATE_IDLE;
- }
-
- /** Invoked when the error message is being cleared. */
- protected void handleResetAfterError() {}
-
- /** Invoked when the help message is being cleared. */
- protected void handleResetAfterHelp() {}
-
- /** True if the dialog supports {@link AuthDialog.DialogSize#SIZE_SMALL}. */
- protected boolean supportsSmallDialog() {
- return false;
- }
-
- /** The string to show when the user must tap to confirm via the button or icon. */
- @StringRes
- protected int getConfirmationPrompt() {
- return R.string.biometric_dialog_tap_confirm;
- }
-
- /** True if require confirmation will be honored when set via the API. */
- protected boolean supportsRequireConfirmation() {
- return false;
- }
-
- /** True if confirmation will be required even if it was not supported/requested. */
- protected boolean forceRequireConfirmation(@Modality int modality) {
- return false;
- }
-
- /** Ignore all events from this (secondary) modality except successful authentication. */
- protected boolean ignoreUnsuccessfulEventsFrom(@Modality int modality,
- String unsuccessfulReason) {
- return false;
- }
-
- /** Create the controller for managing the icons transitions during the prompt.*/
- @NonNull
- protected abstract AuthIconController createIconController();
-
- @Override
- public AuthIconController getLegacyIconController() {
- return mIconController;
- }
-
- @Override
- public void cancelAnimation() {
- animate().cancel();
- }
-
- @Override
- public View asView() {
- return this;
- }
-
- @Override
- public boolean isCoex() {
- return false;
- }
-
- void setPanelController(AuthPanelController panelController) {
- mPanelController = panelController;
- }
- void setPromptInfo(PromptInfo promptInfo) {
- mPromptInfo = promptInfo;
- }
-
- void setCallback(Callback callback) {
- mCallback = callback;
- }
-
- void setBackgroundView(View backgroundView) {
- backgroundView.setOnClickListener(mBackgroundClickListener);
- }
-
- void setUserId(int userId) {
- mUserId = userId;
- }
-
- void setEffectiveUserId(int effectiveUserId) {
- mEffectiveUserId = effectiveUserId;
- }
-
- void setRequireConfirmation(boolean requireConfirmation) {
- mRequireConfirmation = requireConfirmation && supportsRequireConfirmation();
- }
-
- void setJankListener(Animator.AnimatorListener jankListener) {
- mJankListener = jankListener;
- }
-
- private void updatePaddings(int size) {
- final Insets navBarInsets = Utils.getNavbarInsets(mContext);
- if (size != AuthDialog.SIZE_LARGE) {
- if (mPanelController.getPosition() == AuthPanelController.POSITION_LEFT) {
- setPadding(navBarInsets.left, 0, 0, 0);
- } else if (mPanelController.getPosition() == AuthPanelController.POSITION_RIGHT) {
- setPadding(0, 0, navBarInsets.right, 0);
- } else {
- setPadding(0, 0, 0, navBarInsets.bottom);
- }
- } else {
- setPadding(0, 0, 0, 0);
- }
- }
-
- @VisibleForTesting
- final void updateSize(@AuthDialog.DialogSize int newSize) {
- Log.v(TAG, "Current size: " + mSize + " New size: " + newSize);
- updatePaddings(newSize);
- if (newSize == AuthDialog.SIZE_SMALL) {
- mTitleView.setVisibility(View.GONE);
- mSubtitleView.setVisibility(View.GONE);
- mDescriptionView.setVisibility(View.GONE);
- mIndicatorView.setVisibility(View.GONE);
- mNegativeButton.setVisibility(View.GONE);
- mUseCredentialButton.setVisibility(View.GONE);
-
- final float iconPadding = getResources()
- .getDimension(R.dimen.biometric_dialog_icon_padding);
- mIconHolderView.setY(getHeight() - mIconHolderView.getHeight() - iconPadding);
-
- // Subtract the vertical padding from the new height since it's only used to create
- // extra space between the other elements, and not part of the actual icon.
- final int newHeight = mIconHolderView.getHeight() + 2 * (int) iconPadding
- - mIconHolderView.getPaddingTop() - mIconHolderView.getPaddingBottom();
- mPanelController.updateForContentDimensions(mLayoutParams.mMediumWidth, newHeight,
- 0 /* animateDurationMs */);
-
- mSize = newSize;
- } else if (mSize == AuthDialog.SIZE_SMALL && newSize == AuthDialog.SIZE_MEDIUM) {
- if (mDialogSizeAnimating) {
- return;
- }
- mDialogSizeAnimating = true;
-
- // Animate the icon back to original position
- final ValueAnimator iconAnimator =
- ValueAnimator.ofFloat(mIconHolderView.getY(), mIconOriginalY);
- iconAnimator.addUpdateListener((animation) -> {
- mIconHolderView.setY((float) animation.getAnimatedValue());
- });
-
- // Animate the text
- final ValueAnimator opacityAnimator = ValueAnimator.ofFloat(0, 1);
- opacityAnimator.addUpdateListener((animation) -> {
- final float opacity = (float) animation.getAnimatedValue();
- mTitleView.setAlpha(opacity);
- mIndicatorView.setAlpha(opacity);
- mNegativeButton.setAlpha(opacity);
- mCancelButton.setAlpha(opacity);
- mTryAgainButton.setAlpha(opacity);
-
- if (!TextUtils.isEmpty(mSubtitleView.getText())) {
- mSubtitleView.setAlpha(opacity);
- }
- if (!TextUtils.isEmpty(mDescriptionView.getText())) {
- mDescriptionView.setAlpha(opacity);
- }
- });
-
- // Choreograph together
- final AnimatorSet as = new AnimatorSet();
- as.setDuration(mAnimationDurationShort);
- as.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
- mTitleView.setVisibility(View.VISIBLE);
- mIndicatorView.setVisibility(View.VISIBLE);
-
- if (isDeviceCredentialAllowed()) {
- mUseCredentialButton.setVisibility(View.VISIBLE);
- } else {
- mNegativeButton.setVisibility(View.VISIBLE);
- }
- if (supportsManualRetry()) {
- mTryAgainButton.setVisibility(View.VISIBLE);
- }
-
- if (!TextUtils.isEmpty(mSubtitleView.getText())) {
- mSubtitleView.setVisibility(View.VISIBLE);
- }
- if (!TextUtils.isEmpty(mDescriptionView.getText())) {
- mDescriptionView.setVisibility(View.VISIBLE);
- }
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- mSize = newSize;
- mDialogSizeAnimating = false;
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager,
- AuthBiometricView.this);
- }
- });
-
- if (mJankListener != null) {
- as.addListener(mJankListener);
- }
- as.play(iconAnimator).with(opacityAnimator);
- as.start();
- // Animate the panel
- mPanelController.updateForContentDimensions(mLayoutParams.mMediumWidth,
- mLayoutParams.mMediumHeight,
- AuthDialog.ANIMATE_SMALL_TO_MEDIUM_DURATION_MS);
- } else if (newSize == AuthDialog.SIZE_MEDIUM) {
- mPanelController.updateForContentDimensions(mLayoutParams.mMediumWidth,
- mLayoutParams.mMediumHeight,
- 0 /* animateDurationMs */);
- mSize = newSize;
- } else if (newSize == AuthDialog.SIZE_LARGE) {
- final float translationY = getResources().getDimension(
- R.dimen.biometric_dialog_medium_to_large_translation_offset);
- final AuthBiometricView biometricView = this;
-
- // Translate at full duration
- final ValueAnimator translationAnimator = ValueAnimator.ofFloat(
- biometricView.getY(), biometricView.getY() - translationY);
- translationAnimator.setDuration(mAnimationDurationLong);
- translationAnimator.addUpdateListener((animation) -> {
- final float translation = (float) animation.getAnimatedValue();
- biometricView.setTranslationY(translation);
- });
- translationAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- if (biometricView.getParent() instanceof ViewGroup) {
- ((ViewGroup) biometricView.getParent()).removeView(biometricView);
- }
- mSize = newSize;
- }
- });
-
- // Opacity to 0 in half duration
- final ValueAnimator opacityAnimator = ValueAnimator.ofFloat(1, 0);
- opacityAnimator.setDuration(mAnimationDurationLong / 2);
- opacityAnimator.addUpdateListener((animation) -> {
- final float opacity = (float) animation.getAnimatedValue();
- biometricView.setAlpha(opacity);
- });
-
- mPanelController.setUseFullScreen(true);
- mPanelController.updateForContentDimensions(
- mPanelController.getContainerWidth(),
- mPanelController.getContainerHeight(),
- mAnimationDurationLong);
-
- // Start the animations together
- AnimatorSet as = new AnimatorSet();
- List<Animator> animators = new ArrayList<>();
- animators.add(translationAnimator);
- animators.add(opacityAnimator);
-
- if (mJankListener != null) {
- as.addListener(mJankListener);
- }
- as.playTogether(animators);
- as.setDuration(mAnimationDurationLong * 2 / 3);
- as.start();
- } else {
- Log.e(TAG, "Unknown transition from: " + mSize + " to: " + newSize);
- }
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- }
-
- protected boolean supportsManualRetry() {
- return false;
- }
-
- /**
- * Updates mIconView animation on updates to fold state, device rotation, or rear display mode
- * @param animation new asset to use for iconw
- */
- public void updateIconViewAnimation(int animation) {
- mIconView.setAnimation(animation);
- }
-
- public void updateState(@BiometricState int newState) {
- Log.d(TAG, "newState: " + newState);
-
- mIconController.updateState(mState, newState);
-
- switch (newState) {
- case STATE_AUTHENTICATING_ANIMATING_IN:
- case STATE_AUTHENTICATING:
- removePendingAnimations();
- if (mRequireConfirmation) {
- mConfirmButton.setEnabled(false);
- mConfirmButton.setVisibility(View.VISIBLE);
- }
- break;
-
- case STATE_AUTHENTICATED:
- removePendingAnimations();
- if (mSize != AuthDialog.SIZE_SMALL) {
- mConfirmButton.setVisibility(View.GONE);
- mNegativeButton.setVisibility(View.GONE);
- mUseCredentialButton.setVisibility(View.GONE);
- mCancelButton.setVisibility(View.GONE);
- mIndicatorView.setVisibility(View.INVISIBLE);
- }
- announceForAccessibility(getResources()
- .getString(R.string.biometric_dialog_authenticated));
- if (mState == STATE_PENDING_CONFIRMATION) {
- mHandler.postDelayed(() -> mCallback.onAction(
- Callback.ACTION_AUTHENTICATED_AND_CONFIRMED),
- getDelayAfterAuthenticatedDurationMs());
- } else {
- mHandler.postDelayed(() -> mCallback.onAction(Callback.ACTION_AUTHENTICATED),
- getDelayAfterAuthenticatedDurationMs());
- }
- break;
-
- case STATE_PENDING_CONFIRMATION:
- removePendingAnimations();
- mNegativeButton.setVisibility(View.GONE);
- mCancelButton.setVisibility(View.VISIBLE);
- mUseCredentialButton.setVisibility(View.GONE);
- // forced confirmations (multi-sensor) use the icon view as the confirm button
- mConfirmButton.setEnabled(mRequireConfirmation);
- mConfirmButton.setVisibility(mRequireConfirmation ? View.VISIBLE : View.GONE);
- mIndicatorView.setTextColor(mTextColorHint);
- mIndicatorView.setText(getConfirmationPrompt());
- mIndicatorView.setVisibility(View.VISIBLE);
- break;
-
- case STATE_ERROR:
- if (mSize == AuthDialog.SIZE_SMALL) {
- updateSize(AuthDialog.SIZE_MEDIUM);
- }
- break;
-
- default:
- Log.w(TAG, "Unhandled state: " + newState);
- break;
- }
-
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- mState = newState;
- }
-
- public void onOrientationChanged() {
- // Update padding and AuthPanel outline by calling updateSize when the orientation changed.
- updateSize(mSize);
- }
-
- public void onDialogAnimatedIn(boolean fingerprintWasStarted) {
- updateState(STATE_AUTHENTICATING);
- }
-
- public void onAuthenticationSucceeded(@Modality int modality) {
- removePendingAnimations();
- if (mRequireConfirmation || forceRequireConfirmation(modality)) {
- updateState(STATE_PENDING_CONFIRMATION);
- } else {
- updateState(STATE_AUTHENTICATED);
- }
- }
-
- /**
- * Notify the view that auth has failed.
- *
- * @param modality sensor modality that failed
- * @param failureReason message
- */
- public void onAuthenticationFailed(
- @Modality int modality, @Nullable String failureReason) {
- if (ignoreUnsuccessfulEventsFrom(modality, failureReason)) {
- return;
- }
-
- showTemporaryMessage(failureReason, mResetErrorRunnable);
- updateState(STATE_ERROR);
- }
-
- /**
- * Notify the view that an error occurred.
- *
- * @param modality sensor modality that failed
- * @param error message
- */
- public void onError(@Modality int modality, String error) {
- if (ignoreUnsuccessfulEventsFrom(modality, error)) {
- return;
- }
-
- showTemporaryMessage(error, mResetErrorRunnable);
- updateState(STATE_ERROR);
-
- mHandler.postDelayed(() -> mCallback.onAction(Callback.ACTION_ERROR),
- mAnimationDurationHideDialog);
- }
-
- /**
- * Show a help message to the user.
- *
- * @param modality sensor modality
- * @param help message
- */
- public void onHelp(@Modality int modality, String help) {
- if (ignoreUnsuccessfulEventsFrom(modality, help)) {
- return;
- }
- if (mSize != AuthDialog.SIZE_MEDIUM) {
- Log.w(TAG, "Help received in size: " + mSize);
- return;
- }
- if (TextUtils.isEmpty(help)) {
- Log.w(TAG, "Ignoring blank help message");
- return;
- }
-
- showTemporaryMessage(help, mResetHelpRunnable);
- updateState(STATE_HELP);
- }
-
- public void onSaveState(@NonNull Bundle outState) {
- outState.putInt(AuthDialog.KEY_BIOMETRIC_CONFIRM_VISIBILITY,
- mConfirmButton.getVisibility());
- outState.putInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY,
- mTryAgainButton.getVisibility());
- outState.putInt(AuthDialog.KEY_BIOMETRIC_STATE, mState);
- outState.putString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING,
- mIndicatorView.getText() != null ? mIndicatorView.getText().toString() : "");
- outState.putBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING,
- mHandler.hasCallbacks(mResetErrorRunnable));
- outState.putBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_HELP_SHOWING,
- mHandler.hasCallbacks(mResetHelpRunnable));
- outState.putInt(AuthDialog.KEY_BIOMETRIC_DIALOG_SIZE, mSize);
- }
-
- /**
- * Invoked after inflation but before being attached to window.
- * @param savedState
- */
- public void restoreState(@Nullable Bundle savedState) {
- mSavedState = savedState;
- }
- private void setTextOrHide(TextView view, CharSequence charSequence) {
- if (TextUtils.isEmpty(charSequence)) {
- view.setVisibility(View.GONE);
- } else {
- view.setText(charSequence);
- }
-
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- }
-
- // Remove all pending icon and text animations
- private void removePendingAnimations() {
- mHandler.removeCallbacks(mResetHelpRunnable);
- mHandler.removeCallbacks(mResetErrorRunnable);
- }
-
- private void showTemporaryMessage(String message, Runnable resetMessageRunnable) {
- removePendingAnimations();
- mIndicatorView.setText(message);
- mIndicatorView.setTextColor(mTextColorError);
- mIndicatorView.setVisibility(View.VISIBLE);
- // select to enable marquee unless a screen reader is enabled
- mIndicatorView.setSelected(!mAccessibilityManager.isEnabled()
- || !mAccessibilityManager.isTouchExplorationEnabled());
- mHandler.postDelayed(resetMessageRunnable, mAnimationDurationHideDialog);
-
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (mSavedState != null) {
- updateState(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_STATE));
- }
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mTitleView = findViewById(R.id.title);
- mSubtitleView = findViewById(R.id.subtitle);
- mDescriptionView = findViewById(R.id.description);
- mIconViewOverlay = findViewById(R.id.biometric_icon_overlay);
- mIconView = findViewById(R.id.biometric_icon);
- mIconHolderView = findViewById(R.id.biometric_icon_frame);
- mIndicatorView = findViewById(R.id.indicator);
-
- // Negative-side (left) buttons
- mNegativeButton = findViewById(R.id.button_negative);
- mCancelButton = findViewById(R.id.button_cancel);
- mUseCredentialButton = findViewById(R.id.button_use_credential);
-
- // Positive-side (right) buttons
- mConfirmButton = findViewById(R.id.button_confirm);
- mTryAgainButton = findViewById(R.id.button_try_again);
-
- mNegativeButton.setOnClickListener((view) -> {
- mCallback.onAction(Callback.ACTION_BUTTON_NEGATIVE);
- });
-
- mCancelButton.setOnClickListener((view) -> {
- mCallback.onAction(Callback.ACTION_USER_CANCELED);
- });
-
- mUseCredentialButton.setOnClickListener((view) -> {
- startTransitionToCredentialUI(false /* isError */);
- });
-
- mConfirmButton.setOnClickListener((view) -> {
- updateState(STATE_AUTHENTICATED);
- });
-
- mTryAgainButton.setOnClickListener((view) -> {
- updateState(STATE_AUTHENTICATING);
- mCallback.onAction(Callback.ACTION_BUTTON_TRY_AGAIN);
- mTryAgainButton.setVisibility(View.GONE);
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- });
-
- mIconController = createIconController();
- if (mIconController.getActsAsConfirmButton()) {
- mIconViewOverlay.setOnClickListener((view)->{
- if (mState == STATE_PENDING_CONFIRMATION) {
- updateState(STATE_AUTHENTICATED);
- }
- });
- mIconView.setOnClickListener((view) -> {
- if (mState == STATE_PENDING_CONFIRMATION) {
- updateState(STATE_AUTHENTICATED);
- }
- });
- }
- }
-
- /**
- * Kicks off the animation process and invokes the callback.
- *
- * @param isError if this was triggered due to an error and not a user action (unused,
- * previously for haptics).
- */
- @Override
- public void startTransitionToCredentialUI(boolean isError) {
- updateSize(AuthDialog.SIZE_LARGE);
- mCallback.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- mTitleView.setText(mPromptInfo.getTitle());
-
- // setSelected could make marquee work
- mTitleView.setSelected(true);
- mSubtitleView.setSelected(true);
- // make description view become scrollable
- mDescriptionView.setMovementMethod(new ScrollingMovementMethod());
-
- if (isDeviceCredentialAllowed()) {
- final CharSequence credentialButtonText;
- @Utils.CredentialType final int credentialType =
- Utils.getCredentialType(mLockPatternUtils, mEffectiveUserId);
- switch (credentialType) {
- case Utils.CREDENTIAL_PIN:
- credentialButtonText =
- getResources().getString(R.string.biometric_dialog_use_pin);
- break;
- case Utils.CREDENTIAL_PATTERN:
- credentialButtonText =
- getResources().getString(R.string.biometric_dialog_use_pattern);
- break;
- case Utils.CREDENTIAL_PASSWORD:
- default:
- credentialButtonText =
- getResources().getString(R.string.biometric_dialog_use_password);
- break;
- }
-
- mNegativeButton.setVisibility(View.GONE);
-
- mUseCredentialButton.setText(credentialButtonText);
- mUseCredentialButton.setVisibility(View.VISIBLE);
- } else {
- mNegativeButton.setText(mPromptInfo.getNegativeButtonText());
- }
-
- setTextOrHide(mSubtitleView, mPromptInfo.getSubtitle());
- setTextOrHide(mDescriptionView, mPromptInfo.getDescription());
-
- if (mSavedState == null) {
- updateState(STATE_AUTHENTICATING_ANIMATING_IN);
- } else {
- // Restore as much state as possible first
- updateState(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_STATE));
-
- // Restore positive button(s) state
- mConfirmButton.setVisibility(
- mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_CONFIRM_VISIBILITY));
- if (mConfirmButton.getVisibility() == View.GONE) {
- setRequireConfirmation(false);
- }
- mTryAgainButton.setVisibility(
- mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY));
-
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
-
- mIconController.setDeactivated(true);
-
- // Empty the handler, otherwise things like ACTION_AUTHENTICATED may be duplicated once
- // the new dialog is restored.
- mHandler.removeCallbacksAndMessages(null /* all */);
- }
-
- /**
- * Contains all of the testable logic that should be invoked when {@link #onMeasure(int, int)}
- * is invoked. In addition, this allows subclasses to implement custom measuring logic while
- * allowing the base class to have common code to apply the custom measurements.
- *
- * @param width Width to constrain the measurements to.
- * @param height Height to constrain the measurements to.
- * @return See {@link AuthDialog.LayoutParams}
- */
- @NonNull
- AuthDialog.LayoutParams onMeasureInternal(int width, int height) {
- int totalHeight = 0;
- final int numChildren = getChildCount();
- for (int i = 0; i < numChildren; i++) {
- final View child = getChildAt(i);
-
- if (child.getId() == R.id.space_above_icon
- || child.getId() == R.id.space_below_icon
- || child.getId() == R.id.button_bar) {
- child.measure(
- MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(child.getLayoutParams().height,
- MeasureSpec.EXACTLY));
- } else if (child.getId() == R.id.biometric_icon_frame) {
- final View iconView = findViewById(R.id.biometric_icon);
- child.measure(
- MeasureSpec.makeMeasureSpec(iconView.getLayoutParams().width,
- MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(iconView.getLayoutParams().height,
- MeasureSpec.EXACTLY));
- } else if (child.getId() == R.id.biometric_icon) {
- child.measure(
- MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
- } else {
- child.measure(
- MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
- }
-
- if (child.getVisibility() != View.GONE) {
- totalHeight += child.getMeasuredHeight();
- }
- }
-
- return new AuthDialog.LayoutParams(width, totalHeight);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = MeasureSpec.getSize(widthMeasureSpec);
- int height = MeasureSpec.getSize(heightMeasureSpec);
-
- if (mUseCustomBpSize) {
- width = mCustomBpWidth;
- height = mCustomBpHeight;
- } else {
- width = Math.min(width, height);
- }
-
- mLayoutParams = onMeasureInternal(width, height);
-
- final Insets navBarInsets = Utils.getNavbarInsets(mContext);
- final int navBarHeight = navBarInsets.bottom;
- final int navBarWidth;
- if (mPanelController.getPosition() == AuthPanelController.POSITION_LEFT) {
- navBarWidth = navBarInsets.left;
- } else if (mPanelController.getPosition() == AuthPanelController.POSITION_RIGHT) {
- navBarWidth = navBarInsets.right;
- } else {
- navBarWidth = 0;
- }
-
- // The actual auth dialog w/h should include navigation bar size.
- if (navBarWidth != 0 || navBarHeight != 0) {
- mLayoutParams = new AuthDialog.LayoutParams(
- mLayoutParams.mMediumWidth + navBarWidth,
- mLayoutParams.mMediumHeight + navBarInsets.bottom);
- }
-
- setMeasuredDimension(mLayoutParams.mMediumWidth, mLayoutParams.mMediumHeight);
- }
-
- @Override
- public void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- // Start with initial size only once. Subsequent layout changes don't matter since we
- // only care about the initial icon position.
- if (mIconOriginalY == 0) {
- mIconOriginalY = mIconHolderView.getY();
- if (mSavedState == null) {
- updateSize(!mRequireConfirmation && supportsSmallDialog() ? AuthDialog.SIZE_SMALL
- : AuthDialog.SIZE_MEDIUM);
- } else {
- updateSize(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_DIALOG_SIZE));
-
- // Restore indicator text state only after size has been restored
- final String indicatorText =
- mSavedState.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING);
- if (mSavedState.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_HELP_SHOWING)) {
- onHelp(TYPE_NONE, indicatorText);
- } else if (mSavedState.getBoolean(
- AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING)) {
- onAuthenticationFailed(TYPE_NONE, indicatorText);
- }
- }
- }
- }
-
- private boolean isDeviceCredentialAllowed() {
- return Utils.isDeviceCredentialAllowed(mPromptInfo);
- }
-
- public LottieAnimationView getIconView() {
- return mIconView;
- }
-
- @AuthDialog.DialogSize int getSize() {
- return mSize;
- }
-
- /** If authentication has successfully occurred and the view is done. */
- boolean isAuthenticated() {
- return mState == STATE_AUTHENTICATED;
- }
-
- /** If authentication is currently in progress. */
- boolean isAuthenticating() {
- return mState == STATE_AUTHENTICATING;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricViewAdapter.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricViewAdapter.kt
deleted file mode 100644
index 68db564..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricViewAdapter.kt
+++ /dev/null
@@ -1,56 +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.biometrics
-
-import android.hardware.biometrics.BiometricAuthenticator
-import android.os.Bundle
-import android.view.View
-
-/** TODO(b/251476085): Temporary interface while legacy biometric prompt is around. */
-@Deprecated("temporary adapter while migrating biometric prompt - do not expand")
-interface AuthBiometricViewAdapter {
- val legacyIconController: AuthIconController?
-
- fun onDialogAnimatedIn(fingerprintWasStarted: Boolean)
-
- fun onAuthenticationSucceeded(@BiometricAuthenticator.Modality modality: Int)
-
- fun onAuthenticationFailed(
- @BiometricAuthenticator.Modality modality: Int,
- failureReason: String
- )
-
- fun onError(@BiometricAuthenticator.Modality modality: Int, error: String)
-
- fun onHelp(@BiometricAuthenticator.Modality modality: Int, help: String)
-
- fun startTransitionToCredentialUI(isError: Boolean)
-
- fun requestLayout()
-
- fun onSaveState(bundle: Bundle?)
-
- fun restoreState(bundle: Bundle?)
-
- fun onOrientationChanged()
-
- fun cancelAnimation()
-
- fun isCoex(): Boolean
-
- fun asView(): View
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 7464c88..c7d7fe3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -17,9 +17,7 @@
package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
-import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-
import static com.android.internal.jank.InteractionJankMonitor.CUJ_BIOMETRIC_PROMPT_TRANSITION;
import android.animation.Animator;
@@ -35,7 +33,6 @@
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Binder;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -70,15 +67,16 @@
import com.android.systemui.biometrics.AuthController.ScaleFactorProvider;
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
-import com.android.systemui.biometrics.domain.model.BiometricModalities;
+import com.android.systemui.biometrics.shared.model.BiometricModalities;
import com.android.systemui.biometrics.ui.BiometricPromptLayout;
import com.android.systemui.biometrics.ui.CredentialView;
import com.android.systemui.biometrics.ui.binder.BiometricViewBinder;
+import com.android.systemui.biometrics.ui.binder.BiometricViewSizeBinder;
+import com.android.systemui.biometrics.ui.binder.Spaghetti;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -96,7 +94,10 @@
/**
* Top level container/controller for the BiometricPrompt UI.
+ *
+ * @deprecated TODO(b/287311775): remove and merge view/layouts into new prompt.
*/
+@Deprecated
public class AuthContainerView extends LinearLayout
implements AuthDialog, WakefulnessLifecycle.Observer, CredentialView.Host {
@@ -104,6 +105,7 @@
private static final int ANIMATION_DURATION_SHOW_MS = 250;
private static final int ANIMATION_DURATION_AWAY_MS = 350;
+ private static final int ANIMATE_CREDENTIAL_START_DELAY_MS = 300;
private static final int STATE_UNKNOWN = 0;
private static final int STATE_ANIMATING_IN = 1;
@@ -138,16 +140,16 @@
private final InteractionJankMonitor mInteractionJankMonitor;
private final CoroutineScope mApplicationCoroutineScope;
- // TODO: these should be migrated out once ready
+ // TODO(b/287311775): these should be migrated out once ready
private final Provider<PromptCredentialInteractor> mPromptCredentialInteractor;
private final @NonNull Provider<PromptSelectorInteractor> mPromptSelectorInteractorProvider;
- // TODO(b/251476085): these should be migrated out of the view
+ // TODO(b/287311775): these should be migrated out of the view
private final Provider<CredentialViewModel> mCredentialViewModelProvider;
private final PromptViewModel mPromptViewModel;
@VisibleForTesting final BiometricCallback mBiometricCallback;
- @Nullable private AuthBiometricViewAdapter mBiometricView;
+ @Nullable private Spaghetti mBiometricView;
@Nullable private View mCredentialView;
private final AuthPanelController mPanelController;
private final FrameLayout mFrameLayout;
@@ -166,7 +168,7 @@
// HAT received from LockSettingsService when credential is verified.
@Nullable private byte[] mCredentialAttestation;
- // TODO(b/251476085): remove when legacy prompt is replaced
+ // TODO(b/287311775): remove when legacy prompt is replaced
@Deprecated
static class Config {
Context mContext;
@@ -184,42 +186,50 @@
}
@VisibleForTesting
- final class BiometricCallback implements AuthBiometricView.Callback {
+ final class BiometricCallback implements Spaghetti.Callback {
@Override
- public void onAction(int action) {
- switch (action) {
- case AuthBiometricView.Callback.ACTION_AUTHENTICATED:
- animateAway(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED);
- break;
- case AuthBiometricView.Callback.ACTION_USER_CANCELED:
- sendEarlyUserCanceled();
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
- break;
- case AuthBiometricView.Callback.ACTION_BUTTON_NEGATIVE:
- animateAway(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE);
- break;
- case AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN:
- mFailedModalities.clear();
- mConfig.mCallback.onTryAgainPressed(getRequestId());
- break;
- case AuthBiometricView.Callback.ACTION_ERROR:
- animateAway(AuthDialogCallback.DISMISSED_ERROR);
- break;
- case AuthBiometricView.Callback.ACTION_USE_DEVICE_CREDENTIAL:
- mConfig.mCallback.onDeviceCredentialPressed(getRequestId());
- mHandler.postDelayed(() -> {
- addCredentialView(false /* animatePanel */, true /* animateContents */);
- }, mConfig.mSkipAnimation ? 0 : AuthDialog.ANIMATE_CREDENTIAL_START_DELAY_MS);
- break;
- case AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR:
- mConfig.mCallback.onStartFingerprintNow(getRequestId());
- break;
- case AuthBiometricView.Callback.ACTION_AUTHENTICATED_AND_CONFIRMED:
- animateAway(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE);
- break;
- default:
- Log.e(TAG, "Unhandled action: " + action);
- }
+ public void onAuthenticated() {
+ animateAway(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED);
+ }
+
+ @Override
+ public void onUserCanceled() {
+ sendEarlyUserCanceled();
+ animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ }
+
+ @Override
+ public void onButtonNegative() {
+ animateAway(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE);
+ }
+
+ @Override
+ public void onButtonTryAgain() {
+ mFailedModalities.clear();
+ mConfig.mCallback.onTryAgainPressed(getRequestId());
+ }
+
+ @Override
+ public void onError() {
+ animateAway(AuthDialogCallback.DISMISSED_ERROR);
+ }
+
+ @Override
+ public void onUseDeviceCredential() {
+ mConfig.mCallback.onDeviceCredentialPressed(getRequestId());
+ mHandler.postDelayed(() -> {
+ addCredentialView(false /* animatePanel */, true /* animateContents */);
+ }, mConfig.mSkipAnimation ? 0 : ANIMATE_CREDENTIAL_START_DELAY_MS);
+ }
+
+ @Override
+ public void onStartDelayedFingerprintSensor() {
+ mConfig.mCallback.onStartFingerprintNow(getRequestId());
+ }
+
+ @Override
+ public void onAuthenticatedAndConfirmed() {
+ animateAway(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE);
}
}
@@ -355,14 +365,10 @@
mCredentialViewModelProvider = credentialViewModelProvider;
mPromptViewModel = promptViewModel;
- if (featureFlags.isEnabled(Flags.BIOMETRIC_BP_STRONG)) {
- showPrompt(config, layoutInflater, promptViewModel,
- Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
- Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds),
- vibratorHelper, featureFlags);
- } else {
- showLegacyPrompt(config, layoutInflater, fpProps, faceProps);
- }
+ showPrompt(config, layoutInflater, promptViewModel,
+ Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
+ Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds),
+ vibratorHelper, featureFlags);
// TODO: De-dupe the logic with AuthCredentialPasswordView
setOnKeyListener((v, keyCode, event) -> {
@@ -398,7 +404,8 @@
R.layout.biometric_prompt_layout, null, false);
mBiometricView = BiometricViewBinder.bind(view, viewModel, mPanelController,
// TODO(b/201510778): This uses the wrong timeout in some cases
- getJankListener(view, TRANSIT, AuthDialog.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS),
+ getJankListener(view, TRANSIT,
+ BiometricViewSizeBinder.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS),
mBackgroundView, mBiometricCallback, mApplicationCoroutineScope,
vibratorHelper, featureFlags);
@@ -412,60 +419,6 @@
}
}
- // TODO(b/251476085): remove entirely
- private void showLegacyPrompt(@NonNull Config config, @NonNull LayoutInflater layoutInflater,
- @Nullable List<FingerprintSensorPropertiesInternal> fpProps,
- @Nullable List<FaceSensorPropertiesInternal> faceProps
- ) {
- // Inflate biometric view only if necessary.
- if (Utils.isBiometricAllowed(mConfig.mPromptInfo)) {
- final FingerprintSensorPropertiesInternal fpProperties =
- Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds);
- final FaceSensorPropertiesInternal faceProperties =
- Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds);
-
- if (fpProperties != null && faceProperties != null) {
- final AuthBiometricFingerprintAndFaceView fingerprintAndFaceView =
- (AuthBiometricFingerprintAndFaceView) layoutInflater.inflate(
- R.layout.auth_biometric_fingerprint_and_face_view, null, false);
- fingerprintAndFaceView.setSensorProperties(fpProperties);
- fingerprintAndFaceView.setScaleFactorProvider(config.mScaleProvider);
- fingerprintAndFaceView.updateOverrideIconLayoutParamsSize();
- fingerprintAndFaceView.setFaceClass3(
- faceProperties.sensorStrength == STRENGTH_STRONG);
- mBiometricView = fingerprintAndFaceView;
- } else if (fpProperties != null) {
- final AuthBiometricFingerprintView fpView =
- (AuthBiometricFingerprintView) layoutInflater.inflate(
- R.layout.auth_biometric_fingerprint_view, null, false);
- fpView.setSensorProperties(fpProperties);
- fpView.setScaleFactorProvider(config.mScaleProvider);
- fpView.updateOverrideIconLayoutParamsSize();
- mBiometricView = fpView;
- } else if (faceProperties != null) {
- mBiometricView = (AuthBiometricFaceView) layoutInflater.inflate(
- R.layout.auth_biometric_face_view, null, false);
- } else {
- Log.e(TAG, "No sensors found!");
- }
- }
-
- // init view before showing
- if (mBiometricView != null) {
- final AuthBiometricView view = (AuthBiometricView) mBiometricView;
- view.setRequireConfirmation(mConfig.mRequireConfirmation);
- view.setPanelController(mPanelController);
- view.setPromptInfo(mConfig.mPromptInfo);
- view.setCallback(mBiometricCallback);
- view.setBackgroundView(mBackgroundView);
- view.setUserId(mConfig.mUserId);
- view.setEffectiveUserId(mEffectiveUserId);
- // TODO(b/201510778): This uses the wrong timeout in some cases (remove w/ above)
- view.setJankListener(getJankListener(view, TRANSIT,
- AuthDialog.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS));
- }
- }
-
private void onBackInvoked() {
sendEarlyUserCanceled();
animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
@@ -533,9 +486,6 @@
@Override
public void onOrientationChanged() {
maybeUpdatePositionForUdfps(true /* invalidate */);
- if (mBiometricView != null) {
- mBiometricView.onOrientationChanged();
- }
}
@Override
@@ -621,10 +571,6 @@
}
private static boolean shouldUpdatePositionForUdfps(@NonNull View view) {
- // TODO(b/251476085): legacy view (delete when removed)
- if (view instanceof AuthBiometricFingerprintView) {
- return ((AuthBiometricFingerprintView) view).isUdfps();
- }
if (view instanceof BiometricPromptLayout) {
// this will force the prompt to align itself on the edge of the screen
// instead of centering (temporary workaround to prevent small implicit view
@@ -672,7 +618,6 @@
if (invalidate) {
mPanelView.invalidateOutline();
- mBiometricView.requestLayout();
}
return true;
@@ -702,11 +647,7 @@
}
@Override
- public void show(WindowManager wm, @Nullable Bundle savedState) {
- if (mBiometricView != null) {
- mBiometricView.restoreState(savedState);
- }
-
+ public void show(WindowManager wm) {
wm.addView(this, getLayoutParams(mWindowToken, mConfig.mPromptInfo.getTitle()));
}
@@ -781,7 +722,7 @@
if (mFailedModalities.contains(TYPE_FACE)) {
Log.d(TAG, "retrying failed modalities (pointer down)");
mFailedModalities.remove(TYPE_FACE);
- mBiometricCallback.onAction(AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN);
+ mBiometricCallback.onButtonTryAgain();
}
} else {
Log.e(TAG, "onPointerDown(): mBiometricView is null");
@@ -789,21 +730,6 @@
}
@Override
- public void onSaveState(@NonNull Bundle outState) {
- outState.putBoolean(AuthDialog.KEY_CONTAINER_GOING_AWAY,
- mContainerState == STATE_ANIMATING_OUT);
- // In the case where biometric and credential are both allowed, we can assume that
- // biometric isn't showing if credential is showing since biometric is shown first.
- outState.putBoolean(AuthDialog.KEY_BIOMETRIC_SHOWING,
- mBiometricView != null && mCredentialView == null);
- outState.putBoolean(AuthDialog.KEY_CREDENTIAL_SHOWING, mCredentialView != null);
-
- if (mBiometricView != null) {
- mBiometricView.onSaveState(outState);
- }
- }
-
- @Override
public String getOpPackageName() {
return mConfig.mOpPackageName;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index d5289a4..b752c3b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -50,7 +50,6 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
-import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserManager;
@@ -67,12 +66,11 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.os.SomeArgs;
import com.android.internal.widget.LockPatternUtils;
-import com.android.settingslib.udfps.UdfpsOverlayParams;
-import com.android.settingslib.udfps.UdfpsUtils;
import com.android.systemui.CoreStartable;
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
import com.android.systemui.dagger.SysUISingleton;
@@ -88,8 +86,6 @@
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.Execution;
-import kotlin.Unit;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -103,6 +99,8 @@
import javax.inject.Inject;
import javax.inject.Provider;
+import kotlin.Unit;
+
import kotlinx.coroutines.CoroutineScope;
/**
@@ -967,7 +965,7 @@
skipAnimation = true;
}
- showDialog(args, skipAnimation, null /* savedState */, mPromptViewModelProvider.get());
+ showDialog(args, skipAnimation, mPromptViewModelProvider.get());
}
/**
@@ -1199,7 +1197,7 @@
return mFpEnrolledForUser.getOrDefault(userId, false);
}
- private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState,
+ private void showDialog(SomeArgs args, boolean skipAnimation,
@Nullable PromptViewModel viewModel) {
mCurrentDialogArgs = args;
@@ -1239,7 +1237,6 @@
if (DEBUG) {
Log.d(TAG, "userId: " + userId
- + " savedState: " + savedState
+ " mCurrentDialog: " + mCurrentDialog
+ " newDialog: " + newDialog);
}
@@ -1261,7 +1258,7 @@
if (!promptInfo.isAllowBackgroundAuthentication() && !isOwnerInForeground()) {
cancelIfOwnerIsNotInForeground();
} else {
- mCurrentDialog.show(mWindowManager, savedState);
+ mCurrentDialog.show(mWindowManager);
}
}
@@ -1283,29 +1280,12 @@
public void onConfigurationChanged(Configuration newConfig) {
updateSensorLocations();
- // Save the state of the current dialog (buttons showing, etc)
+ // TODO(b/287311775): consider removing this to retain the UI cleanly vs re-creating
if (mCurrentDialog != null) {
final PromptViewModel viewModel = mCurrentDialog.getViewModel();
- final Bundle savedState = new Bundle();
- mCurrentDialog.onSaveState(savedState);
mCurrentDialog.dismissWithoutCallback(false /* animate */);
mCurrentDialog = null;
-
- // Only show the dialog if necessary. If it was animating out, the dialog is supposed
- // to send its pending callback immediately.
- if (!savedState.getBoolean(AuthDialog.KEY_CONTAINER_GOING_AWAY, false)) {
- final boolean credentialShowing =
- savedState.getBoolean(AuthDialog.KEY_CREDENTIAL_SHOWING);
- if (credentialShowing) {
- // There may be a cleaner way to do this, rather than altering the current
- // authentication's parameters. This gets the job done and should be clear
- // enough for now.
- PromptInfo promptInfo = (PromptInfo) mCurrentDialogArgs.arg1;
- promptInfo.setAuthenticators(Authenticators.DEVICE_CREDENTIAL);
- }
-
- showDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState, viewModel);
- }
+ showDialog(mCurrentDialogArgs, true /* skipAnimation */, viewModel);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
index 3cfc6f2..3fd488c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
@@ -16,59 +16,20 @@
package com.android.systemui.biometrics;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
-import android.os.Bundle;
import android.view.WindowManager;
import com.android.systemui.Dumpable;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
/**
* Interface for the biometric dialog UI.
*
- * TODO(b/251476085): remove along with legacy controller once flag is removed
+ * TODO(b/287311775): remove along with legacy controller once flag is removed
*/
@Deprecated
public interface AuthDialog extends Dumpable {
- String KEY_CONTAINER_GOING_AWAY = "container_going_away";
- String KEY_BIOMETRIC_SHOWING = "biometric_showing";
- String KEY_CREDENTIAL_SHOWING = "credential_showing";
-
- String KEY_BIOMETRIC_CONFIRM_VISIBILITY = "confirm_visibility";
- String KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY = "try_agian_visibility";
- String KEY_BIOMETRIC_STATE = "state";
- String KEY_BIOMETRIC_INDICATOR_STRING = "indicator_string"; // error / help / hint
- String KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING = "error_is_temporary";
- String KEY_BIOMETRIC_INDICATOR_HELP_SHOWING = "hint_is_temporary";
- String KEY_BIOMETRIC_DIALOG_SIZE = "size";
-
- String KEY_BIOMETRIC_SENSOR_TYPE = "sensor_type";
- String KEY_BIOMETRIC_SENSOR_PROPS = "sensor_props";
-
- int SIZE_UNKNOWN = 0;
- /**
- * Minimal UI, showing only biometric icon.
- */
- int SIZE_SMALL = 1;
- /**
- * Normal-sized biometric UI, showing title, icon, buttons, etc.
- */
- int SIZE_MEDIUM = 2;
- /**
- * Full-screen credential UI.
- */
- int SIZE_LARGE = 3;
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({SIZE_UNKNOWN, SIZE_SMALL, SIZE_MEDIUM, SIZE_LARGE})
- @interface DialogSize {}
-
/**
* Parameters used when laying out {@link AuthBiometricView}, its subclasses, and
* {@link AuthPanelController}.
@@ -84,27 +45,10 @@
}
/**
- * Animation duration, from small to medium dialog, including back panel, icon translation, etc
- */
- int ANIMATE_SMALL_TO_MEDIUM_DURATION_MS = 150;
- /**
- * Animation duration from medium to large dialog, including biometric fade out, back panel, etc
- */
- int ANIMATE_MEDIUM_TO_LARGE_DURATION_MS = 450;
- /**
- * Delay before notifying {@link AuthCredentialView} to start animating in.
- */
- int ANIMATE_CREDENTIAL_START_DELAY_MS = ANIMATE_MEDIUM_TO_LARGE_DURATION_MS * 2 / 3;
- /**
- * Animation duration when sliding in credential UI
- */
- int ANIMATE_CREDENTIAL_INITIAL_DURATION_MS = 150;
-
- /**
* Show the dialog.
* @param wm
*/
- void show(WindowManager wm, @Nullable Bundle savedState);
+ void show(WindowManager wm);
/**
* Dismiss the dialog without sending a callback.
@@ -146,12 +90,6 @@
void onPointerDown();
/**
- * Save the current state.
- * @param outState
- */
- void onSaveState(@NonNull Bundle outState);
-
- /**
* Get the client's package name
*/
String getOpPackageName();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt
index f56bb88..958213a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt
@@ -24,7 +24,7 @@
import android.util.Log
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieCompositionFactory
-import com.android.systemui.biometrics.AuthBiometricView.BiometricState
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
private const val TAG = "AuthIconController"
@@ -76,7 +76,7 @@
}
/** Update the icon to reflect the [newState]. */
- fun updateState(@BiometricState lastState: Int, @BiometricState newState: Int) {
+ fun updateState(lastState: BiometricState, newState: BiometricState) {
if (deactivated) {
Log.w(TAG, "Ignoring updateState when deactivated: $newState")
} else {
@@ -85,7 +85,7 @@
}
/** Call during [updateState] if the controller is not [deactivated]. */
- abstract fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int)
+ abstract fun updateIcon(lastState: BiometricState, newState: BiometricState)
/** Called during [onAnimationEnd] if the controller is not [deactivated]. */
open fun handleAnimationEnd(drawable: Drawable) {}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index ea9fe5f..141983b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -25,14 +25,14 @@
import android.hardware.biometrics.BiometricSourceType
import android.util.DisplayMetrics
import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.logging.KeyguardLogger
import com.android.settingslib.Utils
-import com.android.settingslib.udfps.UdfpsOverlayParams
import com.android.systemui.CoreStartable
import com.android.systemui.R
-import com.android.app.animation.Interpolators
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
index b8c0e2c..66fb8ca 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -27,6 +27,7 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.StatusBarState.SHADE
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.util.ViewController
import kotlinx.coroutines.CoroutineScope
@@ -102,9 +103,11 @@
open suspend fun listenForBouncerExpansion(scope: CoroutineScope): Job {
return scope.launch {
primaryBouncerInteractor.bouncerExpansion.map { 1f - it }.collect { expansion: Float ->
- notificationShadeVisible = expansion > 0f
- view.onExpansionChanged(expansion)
- updatePauseAuth()
+ if (statusBarStateController.state != SHADE) {
+ notificationShadeVisible = expansion > 0f
+ view.onExpansionChanged(expansion)
+ updatePauseAuth()
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 11a578b..9ffb770 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -67,11 +67,10 @@
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.FaceAuthApiRequestReason;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.settingslib.udfps.UdfpsOverlayParams;
-import com.android.settingslib.udfps.UdfpsUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.biometrics.dagger.BiometricsBackground;
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
import com.android.systemui.biometrics.udfps.InteractionEvent;
import com.android.systemui.biometrics.udfps.NormalizedTouchData;
import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor;
@@ -105,8 +104,6 @@
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.SystemClock;
-import kotlin.Unit;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -117,7 +114,10 @@
import javax.inject.Inject;
import javax.inject.Provider;
+import kotlin.Unit;
+
import kotlinx.coroutines.ExperimentalCoroutinesApi;
+
/**
* Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events,
* and toggles the UDFPS display mode.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 4031f2f..941df687 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -46,10 +46,9 @@
import androidx.annotation.LayoutRes
import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.settingslib.udfps.UdfpsOverlayParams
-import com.android.settingslib.udfps.UdfpsUtils
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
import com.android.systemui.biometrics.ui.controller.UdfpsKeyguardViewController
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
index 06dee7a..54e6215 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
@@ -26,8 +26,8 @@
import android.util.Log
import android.view.MotionEvent
import android.widget.FrameLayout
-import com.android.settingslib.udfps.UdfpsOverlayParams
import com.android.systemui.R
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
import com.android.systemui.doze.DozeReceiver
private const val TAG = "UdfpsView"
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
index 53dc0e3..f43285f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
@@ -16,7 +16,7 @@
package com.android.systemui.biometrics.dagger
-import com.android.settingslib.udfps.UdfpsUtils
+import com.android.systemui.biometrics.UdfpsUtils
import com.android.systemui.biometrics.data.repository.FacePropertyRepository
import com.android.systemui.biometrics.data.repository.FacePropertyRepositoryImpl
import com.android.systemui.biometrics.data.repository.FaceSettingsRepository
@@ -33,10 +33,10 @@
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor
import com.android.systemui.biometrics.domain.interactor.LogContextInteractorImpl
-import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractor
-import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractorImpl
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractor
+import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractorImpl
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.concurrency.ThreadFactory
import dagger.Binds
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
index a6ad24e..65a2c0a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
@@ -23,9 +23,9 @@
import com.android.systemui.biometrics.Utils.isDeviceCredentialAllowed
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.PromptRepository
-import com.android.systemui.biometrics.domain.model.BiometricModalities
import com.android.systemui.biometrics.domain.model.BiometricOperationInfo
import com.android.systemui.biometrics.domain.model.BiometricPromptRequest
+import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricUserInfo
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.PromptKind
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
index 9a0792e..2a1047a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
@@ -18,8 +18,8 @@
import android.view.MotionEvent
import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.settingslib.udfps.UdfpsOverlayParams
import com.android.systemui.biometrics.AuthController
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
index a3ee220..8fbb250 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
@@ -1,6 +1,7 @@
package com.android.systemui.biometrics.domain.model
import android.hardware.biometrics.PromptInfo
+import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricUserInfo
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/PromptKind.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/PromptKind.kt
index 416fc64..a97e2dc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/PromptKind.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/PromptKind.kt
@@ -17,7 +17,6 @@
package com.android.systemui.biometrics.shared.model
import com.android.systemui.biometrics.Utils
-import com.android.systemui.biometrics.domain.model.BiometricModalities
// TODO(b/251476085): this should eventually replace Utils.CredentialType
/** Credential options for biometric prompt. Shadows [Utils.CredentialType]. */
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt
index eeb0f4c..83b3380 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt
@@ -21,7 +21,7 @@
import android.view.MotionEvent
import android.view.MotionEvent.INVALID_POINTER_ID
import android.view.Surface
-import com.android.settingslib.udfps.UdfpsOverlayParams
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
import com.android.systemui.biometrics.udfps.TouchProcessorResult.Failure
import com.android.systemui.biometrics.udfps.TouchProcessorResult.ProcessedTouch
import com.android.systemui.dagger.SysUISingleton
@@ -41,7 +41,6 @@
previousPointerOnSensorId: Int,
overlayParams: UdfpsOverlayParams,
): TouchProcessorResult {
-
fun preprocess(): PreprocessedTouch {
val touchData = List(event.pointerCount) { event.normalize(it, overlayParams) }
val pointersOnSensor =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/TouchProcessor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/TouchProcessor.kt
index 4bf0ef6..78e1dc0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/TouchProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/TouchProcessor.kt
@@ -17,7 +17,7 @@
package com.android.systemui.biometrics.udfps
import android.view.MotionEvent
-import com.android.settingslib.udfps.UdfpsOverlayParams
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
/**
* Determines whether a finger entered or left the area of the under-display fingerprint sensor
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index b1439fd..d616dcc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -23,7 +23,6 @@
import android.hardware.biometrics.BiometricConstants
import android.hardware.biometrics.BiometricPrompt
import android.hardware.face.FaceManager
-import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.util.Log
import android.view.HapticFeedbackConstants
@@ -43,12 +42,9 @@
import com.android.systemui.biometrics.AuthBiometricFaceIconController
import com.android.systemui.biometrics.AuthBiometricFingerprintAndFaceIconController
import com.android.systemui.biometrics.AuthBiometricFingerprintIconController
-import com.android.systemui.biometrics.AuthBiometricView
-import com.android.systemui.biometrics.AuthBiometricView.Callback
-import com.android.systemui.biometrics.AuthBiometricViewAdapter
import com.android.systemui.biometrics.AuthIconController
import com.android.systemui.biometrics.AuthPanelController
-import com.android.systemui.biometrics.domain.model.BiometricModalities
+import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricModality
import com.android.systemui.biometrics.shared.model.PromptKind
import com.android.systemui.biometrics.shared.model.asBiometricModality
@@ -63,7 +59,6 @@
import com.android.systemui.statusbar.VibratorHelper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
@@ -83,11 +78,11 @@
panelViewController: AuthPanelController,
jankListener: BiometricJankListener,
backgroundView: View,
- legacyCallback: Callback,
+ legacyCallback: Spaghetti.Callback,
applicationScope: CoroutineScope,
vibratorHelper: VibratorHelper,
featureFlags: FeatureFlags,
- ): AuthBiometricViewAdapter {
+ ): Spaghetti {
val accessibilityManager = view.context.getSystemService(AccessibilityManager::class.java)!!
val textColorError =
@@ -141,24 +136,20 @@
subtitleView.text = viewModel.subtitle.first()
// set button listeners
- negativeButton.setOnClickListener {
- legacyCallback.onAction(Callback.ACTION_BUTTON_NEGATIVE)
- }
- cancelButton.setOnClickListener {
- legacyCallback.onAction(Callback.ACTION_USER_CANCELED)
- }
+ negativeButton.setOnClickListener { legacyCallback.onButtonNegative() }
+ cancelButton.setOnClickListener { legacyCallback.onUserCanceled() }
credentialFallbackButton.setOnClickListener {
viewModel.onSwitchToCredential()
- legacyCallback.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL)
+ legacyCallback.onUseDeviceCredential()
}
confirmationButton.setOnClickListener { viewModel.confirmAuthenticated() }
retryButton.setOnClickListener {
viewModel.showAuthenticating(isRetry = true)
- legacyCallback.onAction(Callback.ACTION_BUTTON_TRY_AGAIN)
+ legacyCallback.onButtonTryAgain()
}
// TODO(b/251476085): migrate legacy icon controllers and remove
- var legacyState: Int = viewModel.legacyState.value
+ var legacyState = viewModel.legacyState.value
val iconController =
modalities.asIconController(
view.context,
@@ -219,7 +210,7 @@
oldMode == FingerprintStartMode.Pending &&
newMode == FingerprintStartMode.Delayed
) {
- legacyCallback.onAction(Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR)
+ legacyCallback.onStartDelayedFingerprintSensor()
}
if (newMode.isStarted) {
@@ -246,7 +237,7 @@
.collect { dismissOnClick ->
backgroundView.setOnClickListener {
if (dismissOnClick) {
- legacyCallback.onAction(Callback.ACTION_USER_CANCELED)
+ legacyCallback.onUserCanceled()
} else {
Log.w(TAG, "Ignoring background click")
}
@@ -360,13 +351,11 @@
launch {
delay(authState.delay)
- legacyCallback.onAction(
- if (authState.isAuthenticatedAndExplicitlyConfirmed) {
- Callback.ACTION_AUTHENTICATED_AND_CONFIRMED
- } else {
- Callback.ACTION_AUTHENTICATED
- }
- )
+ if (authState.isAuthenticatedAndExplicitlyConfirmed) {
+ legacyCallback.onAuthenticatedAndConfirmed()
+ } else {
+ legacyCallback.onAuthenticated()
+ }
}
}
}
@@ -428,21 +417,50 @@
* the view model (which will be retained) via the application scope.
*
* Do not reference the [view] for anything other than [asView].
- *
- * TODO(b/251476085): remove after replacing AuthContainerView
*/
-private class Spaghetti(
+@Deprecated("TODO(b/251476085): remove after replacing AuthContainerView")
+class Spaghetti(
private val view: View,
private val viewModel: PromptViewModel,
private val applicationContext: Context,
private val applicationScope: CoroutineScope,
-) : AuthBiometricViewAdapter {
+) {
+
+ @Deprecated("TODO(b/251476085): remove after replacing AuthContainerView")
+ interface Callback {
+ fun onAuthenticated()
+ fun onUserCanceled()
+ fun onButtonNegative()
+ fun onButtonTryAgain()
+ fun onError()
+ fun onUseDeviceCredential()
+ fun onStartDelayedFingerprintSensor()
+ fun onAuthenticatedAndConfirmed()
+ }
+
+ @Deprecated("TODO(b/251476085): remove after replacing AuthContainerView")
+ enum class BiometricState {
+ /** Authentication hardware idle. */
+ STATE_IDLE,
+ /** UI animating in, authentication hardware active. */
+ STATE_AUTHENTICATING_ANIMATING_IN,
+ /** UI animated in, authentication hardware active. */
+ STATE_AUTHENTICATING,
+ /** UI animated in, authentication hardware active. */
+ STATE_HELP,
+ /** Hard error, e.g. ERROR_TIMEOUT. Authentication hardware idle. */
+ STATE_ERROR,
+ /** Authenticated, waiting for user confirmation. Authentication hardware idle. */
+ STATE_PENDING_CONFIRMATION,
+ /** Authenticated, dialog animating away soon. */
+ STATE_AUTHENTICATED,
+ }
private var lifecycleScope: CoroutineScope? = null
private var modalities: BiometricModalities = BiometricModalities()
private var legacyCallback: Callback? = null
- override var legacyIconController: AuthIconController? = null
+ var legacyIconController: AuthIconController? = null
private set
// hacky way to suppress lockout errors
@@ -478,7 +496,7 @@
)
}
- override fun onDialogAnimatedIn(fingerprintWasStarted: Boolean) {
+ fun onDialogAnimatedIn(fingerprintWasStarted: Boolean) {
if (fingerprintWasStarted) {
viewModel.ensureFingerprintHasStarted(isDelayed = false)
viewModel.showAuthenticating(modalities.asDefaultHelpMessage(applicationContext))
@@ -487,7 +505,7 @@
}
}
- override fun onAuthenticationSucceeded(@BiometricAuthenticator.Modality modality: Int) {
+ fun onAuthenticationSucceeded(@BiometricAuthenticator.Modality modality: Int) {
applicationScope.launch {
val authenticatedModality = modality.asBiometricModality()
val msgId = getHelpForSuccessfulAuthentication(authenticatedModality)
@@ -511,7 +529,7 @@
else -> null
}
- override fun onAuthenticationFailed(
+ fun onAuthenticationFailed(
@BiometricAuthenticator.Modality modality: Int,
failureReason: String,
) {
@@ -533,7 +551,7 @@
}
}
- override fun onError(modality: Int, error: String) {
+ fun onError(modality: Int, error: String) {
val errorModality = modality.asBiometricModality()
if (ignoreUnsuccessfulEventsFrom(errorModality, error)) {
return
@@ -546,11 +564,11 @@
authenticateAfterError = modalities.hasFingerprint,
)
delay(BiometricPrompt.HIDE_DIALOG_DELAY.toLong())
- legacyCallback?.onAction(Callback.ACTION_ERROR)
+ legacyCallback?.onError()
}
}
- override fun onHelp(modality: Int, help: String) {
+ fun onHelp(modality: Int, help: String) {
if (ignoreUnsuccessfulEventsFrom(modality.asBiometricModality(), "")) {
return
}
@@ -574,36 +592,20 @@
else -> false
}
- override fun startTransitionToCredentialUI(isError: Boolean) {
+ fun startTransitionToCredentialUI(isError: Boolean) {
applicationScope.launch {
viewModel.onSwitchToCredential()
- legacyCallback?.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL)
+ legacyCallback?.onUseDeviceCredential()
}
}
- override fun requestLayout() {
- // nothing, for legacy view...
- }
-
- override fun restoreState(bundle: Bundle?) {
- // nothing, for legacy view...
- }
-
- override fun onSaveState(bundle: Bundle?) {
- // nothing, for legacy view...
- }
-
- override fun onOrientationChanged() {
- // nothing, for legacy view...
- }
-
- override fun cancelAnimation() {
+ fun cancelAnimation() {
view.animate()?.cancel()
}
- override fun isCoex() = modalities.hasFaceAndFingerprint
+ fun isCoex() = modalities.hasFaceAndFingerprint
- override fun asView() = view
+ fun asView() = view
}
private fun BiometricModalities.asDefaultHelpMessage(context: Context): String =
@@ -638,7 +640,7 @@
iconViewOverlay: LottieAnimationView,
) : AuthBiometricFingerprintAndFaceIconController(context, iconView, iconViewOverlay) {
- private var state: Int? = null
+ private var state: Spaghetti.BiometricState? = null
private val faceController = AuthBiometricFaceIconController(context, iconView)
var faceMode: Boolean = true
@@ -649,11 +651,14 @@
faceController.deactivated = !value
iconView.setImageIcon(null)
iconViewOverlay.setImageIcon(null)
- state?.let { updateIcon(AuthBiometricView.STATE_IDLE, it) }
+ state?.let { updateIcon(Spaghetti.BiometricState.STATE_IDLE, it) }
}
}
- override fun updateIcon(lastState: Int, newState: Int) {
+ override fun updateIcon(
+ lastState: Spaghetti.BiometricState,
+ newState: Spaghetti.BiometricState,
+ ) {
if (deactivated) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index 370b36b..b9af031 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -31,7 +31,6 @@
import androidx.core.view.isGone
import androidx.lifecycle.lifecycleScope
import com.android.systemui.R
-import com.android.systemui.biometrics.AuthDialog
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.ui.BiometricPromptLayout
@@ -47,6 +46,10 @@
/** Helper for [BiometricViewBinder] to handle resize transitions. */
object BiometricViewSizeBinder {
+ private const val ANIMATE_SMALL_TO_MEDIUM_DURATION_MS = 150
+ // TODO(b/201510778): make private when related misuse is fixed
+ const val ANIMATE_MEDIUM_TO_LARGE_DURATION_MS = 450
+
/** Resizes [BiometricPromptLayout] and the [panelViewController] via the [PromptViewModel]. */
fun bind(
view: BiometricPromptLayout,
@@ -134,7 +137,7 @@
)
}
size.isMedium && currentSize.isSmall -> {
- val duration = AuthDialog.ANIMATE_SMALL_TO_MEDIUM_DURATION_MS
+ val duration = ANIMATE_SMALL_TO_MEDIUM_DURATION_MS
panelViewController.updateForContentDimensions(
width,
height,
@@ -165,7 +168,7 @@
)
}
size.isLarge -> {
- val duration = AuthDialog.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS
+ val duration = ANIMATE_MEDIUM_TO_LARGE_DURATION_MS
panelViewController.setUseFullScreen(true)
panelViewController.updateForContentDimensions(
panelViewController.containerWidth,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
index 25fe619..931946a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
@@ -9,7 +9,6 @@
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.animation.Interpolators
import com.android.systemui.R
-import com.android.systemui.biometrics.AuthDialog
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.ui.CredentialPasswordView
import com.android.systemui.biometrics.ui.CredentialPatternView
@@ -22,6 +21,8 @@
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
+private const val ANIMATE_CREDENTIAL_INITIAL_DURATION_MS = 150
+
/**
* View binder for all credential variants of BiometricPrompt, including [CredentialPatternView] and
* [CredentialPasswordView].
@@ -147,7 +148,7 @@
postOnAnimation {
animate()
.translationY(0f)
- .setDuration(AuthDialog.ANIMATE_CREDENTIAL_INITIAL_DURATION_MS.toLong())
+ .setDuration(ANIMATE_CREDENTIAL_INITIAL_DURATION_MS.toLong())
.alpha(1f)
.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
.withLayer()
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index be08932..6269700 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -19,12 +19,12 @@
import android.util.Log
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
-import com.android.systemui.biometrics.AuthBiometricView
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
-import com.android.systemui.biometrics.domain.model.BiometricModalities
+import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricModality
import com.android.systemui.biometrics.shared.model.PromptKind
+import com.android.systemui.biometrics.ui.binder.Spaghetti
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION
import com.android.systemui.statusbar.VibratorHelper
@@ -62,8 +62,8 @@
.distinctUntilChanged()
// TODO(b/251476085): remove after icon controllers are migrated - do not keep this state
- private var _legacyState = MutableStateFlow(AuthBiometricView.STATE_IDLE)
- val legacyState: StateFlow<Int> = _legacyState.asStateFlow()
+ private var _legacyState = MutableStateFlow(Spaghetti.BiometricState.STATE_IDLE)
+ val legacyState: StateFlow<Spaghetti.BiometricState> = _legacyState.asStateFlow()
private val _isAuthenticating: MutableStateFlow<Boolean> = MutableStateFlow(false)
@@ -270,7 +270,7 @@
_isAuthenticated.value = PromptAuthState(false)
_forceMediumSize.value = true
_message.value = PromptMessage.Error(message)
- _legacyState.value = AuthBiometricView.STATE_ERROR
+ _legacyState.value = Spaghetti.BiometricState.STATE_ERROR
if (hapticFeedback) {
vibrator.error(failedModality)
@@ -322,13 +322,13 @@
_forceMediumSize.value = true
_legacyState.value =
if (alreadyAuthenticated && isConfirmationRequired.first()) {
- AuthBiometricView.STATE_PENDING_CONFIRMATION
+ Spaghetti.BiometricState.STATE_PENDING_CONFIRMATION
} else if (alreadyAuthenticated && !isConfirmationRequired.first()) {
- AuthBiometricView.STATE_AUTHENTICATED
+ Spaghetti.BiometricState.STATE_AUTHENTICATED
} else if (clearIconError) {
- AuthBiometricView.STATE_IDLE
+ Spaghetti.BiometricState.STATE_IDLE
} else {
- AuthBiometricView.STATE_HELP
+ Spaghetti.BiometricState.STATE_HELP
}
messageJob?.cancel()
@@ -353,7 +353,7 @@
_message.value =
if (message.isNotBlank()) PromptMessage.Help(message) else PromptMessage.Empty
_forceMediumSize.value = true
- _legacyState.value = AuthBiometricView.STATE_HELP
+ _legacyState.value = Spaghetti.BiometricState.STATE_HELP
messageJob?.cancel()
messageJob = launch {
@@ -373,7 +373,7 @@
_isAuthenticating.value = true
_isAuthenticated.value = PromptAuthState(false)
_message.value = if (message.isBlank()) PromptMessage.Empty else PromptMessage.Help(message)
- _legacyState.value = AuthBiometricView.STATE_AUTHENTICATING
+ _legacyState.value = Spaghetti.BiometricState.STATE_AUTHENTICATING
// reset the try again button(s) after the user attempts a retry
if (isRetry) {
@@ -406,9 +406,9 @@
_message.value = PromptMessage.Empty
_legacyState.value =
if (needsUserConfirmation) {
- AuthBiometricView.STATE_PENDING_CONFIRMATION
+ Spaghetti.BiometricState.STATE_PENDING_CONFIRMATION
} else {
- AuthBiometricView.STATE_AUTHENTICATED
+ Spaghetti.BiometricState.STATE_AUTHENTICATED
}
if (!needsUserConfirmation) {
@@ -449,7 +449,7 @@
_isAuthenticated.value = authState.asExplicitlyConfirmed()
_message.value = PromptMessage.Empty
- _legacyState.value = AuthBiometricView.STATE_AUTHENTICATED
+ _legacyState.value = Spaghetti.BiometricState.STATE_AUTHENTICATED
vibrator.success(authState.authenticatedModality)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
index f2b4e09..c0b2153 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
@@ -28,8 +28,11 @@
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
@@ -47,8 +50,10 @@
val primaryBouncerShowingSoon: StateFlow<Boolean>
val primaryBouncerStartingToHide: StateFlow<Boolean>
val primaryBouncerStartingDisappearAnimation: StateFlow<Runnable?>
+
/** Determines if we want to instantaneously show the primary bouncer instead of translating. */
val primaryBouncerScrimmed: StateFlow<Boolean>
+
/**
* Set how much of the notification panel is showing on the screen.
*
@@ -60,8 +65,23 @@
val panelExpansionAmount: StateFlow<Float>
val keyguardPosition: StateFlow<Float?>
val isBackButtonEnabled: StateFlow<Boolean?>
- /** Determines if user is already unlocked */
- val keyguardAuthenticated: StateFlow<Boolean?>
+
+ /**
+ * Triggers when the user has successfully used biometrics to authenticate. True = biometrics
+ * used to authenticate is Class 3, else false. When null, biometrics haven't authenticated the
+ * device.
+ */
+ val keyguardAuthenticatedBiometrics: StateFlow<Boolean?>
+
+ /**
+ * Triggers when the given userId (Int) has successfully used primary authentication to
+ * authenticate
+ */
+ val keyguardAuthenticatedPrimaryAuth: Flow<Int>
+
+ /** Triggers when the given userId (Int) has requested the bouncer when already authenticated */
+ val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Int>
+
val showMessage: StateFlow<BouncerShowMessageModel?>
val resourceUpdateRequests: StateFlow<Boolean>
val alternateBouncerVisible: StateFlow<Boolean>
@@ -88,7 +108,11 @@
fun setShowMessage(bouncerShowMessageModel: BouncerShowMessageModel?)
- fun setKeyguardAuthenticated(keyguardAuthenticated: Boolean?)
+ fun setKeyguardAuthenticatedBiometrics(keyguardAuthenticatedBiometrics: Boolean?)
+
+ suspend fun setKeyguardAuthenticatedPrimaryAuth(userId: Int)
+
+ suspend fun setUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int)
fun setIsBackButtonEnabled(isBackButtonEnabled: Boolean)
@@ -117,9 +141,11 @@
private val _primaryBouncerDisappearAnimation = MutableStateFlow<Runnable?>(null)
override val primaryBouncerStartingDisappearAnimation =
_primaryBouncerDisappearAnimation.asStateFlow()
+
/** Determines if we want to instantaneously show the primary bouncer instead of translating. */
private val _primaryBouncerScrimmed = MutableStateFlow(false)
override val primaryBouncerScrimmed = _primaryBouncerScrimmed.asStateFlow()
+
/**
* Set how much of the notification panel is showing on the screen.
*
@@ -134,13 +160,26 @@
override val keyguardPosition = _keyguardPosition.asStateFlow()
private val _isBackButtonEnabled = MutableStateFlow<Boolean?>(null)
override val isBackButtonEnabled = _isBackButtonEnabled.asStateFlow()
- private val _keyguardAuthenticated = MutableStateFlow<Boolean?>(null)
- /** Determines if user is already unlocked */
- override val keyguardAuthenticated = _keyguardAuthenticated.asStateFlow()
+
+ /** Whether the user is already unlocked by biometrics */
+ private val _keyguardAuthenticatedBiometrics = MutableStateFlow<Boolean?>(null)
+ override val keyguardAuthenticatedBiometrics = _keyguardAuthenticatedBiometrics.asStateFlow()
+
+ /** Whether the user is unlocked via a primary authentication method (pin/pattern/password). */
+ private val _keyguardAuthenticatedPrimaryAuth = MutableSharedFlow<Int>()
+ override val keyguardAuthenticatedPrimaryAuth: Flow<Int> =
+ _keyguardAuthenticatedPrimaryAuth.asSharedFlow()
+
+ /** Whether the user requested to show the bouncer when device is already authenticated */
+ private val _userRequestedBouncerWhenAlreadyAuthenticated = MutableSharedFlow<Int>()
+ override val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Int> =
+ _userRequestedBouncerWhenAlreadyAuthenticated.asSharedFlow()
+
private val _showMessage = MutableStateFlow<BouncerShowMessageModel?>(null)
override val showMessage = _showMessage.asStateFlow()
private val _resourceUpdateRequests = MutableStateFlow(false)
override val resourceUpdateRequests = _resourceUpdateRequests.asStateFlow()
+
/** Values associated with the AlternateBouncer */
private val _alternateBouncerVisible = MutableStateFlow(false)
override val alternateBouncerVisible = _alternateBouncerVisible.asStateFlow()
@@ -204,8 +243,16 @@
_showMessage.value = bouncerShowMessageModel
}
- override fun setKeyguardAuthenticated(keyguardAuthenticated: Boolean?) {
- _keyguardAuthenticated.value = keyguardAuthenticated
+ override fun setKeyguardAuthenticatedBiometrics(keyguardAuthenticatedBiometrics: Boolean?) {
+ _keyguardAuthenticatedBiometrics.value = keyguardAuthenticatedBiometrics
+ }
+
+ override suspend fun setKeyguardAuthenticatedPrimaryAuth(userId: Int) {
+ _keyguardAuthenticatedPrimaryAuth.emit(userId)
+ }
+
+ override suspend fun setUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int) {
+ _userRequestedBouncerWhenAlreadyAuthenticated.emit(userId)
}
override fun setIsBackButtonEnabled(isBackButtonEnabled: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 9527f32..abddb0a 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -92,6 +92,9 @@
/** Whether the pattern should be visible for the currently-selected user. */
val isPatternVisible: StateFlow<Boolean> = authenticationInteractor.isPatternVisible
+ /** The minimal length of a pattern. */
+ val minPatternLength = authenticationInteractor.minPatternLength
+
init {
if (flags.isEnabled()) {
// Clear the message if moved from throttling to no-longer throttling.
@@ -204,12 +207,24 @@
loggingReason = "successful authentication",
)
} else {
- repository.setMessage(errorMessage(authenticationInteractor.getAuthenticationMethod()))
+ showErrorMessage()
}
return isAuthenticated
}
+ /**
+ * Shows the error message.
+ *
+ * Callers should use this instead of [authenticate] when they know ahead of time that an auth
+ * attempt will fail but aren't interested in the other side effects like triggering throttling.
+ * For example, if the user entered a pattern that's too short, the system can show the error
+ * message without having the attempt trigger throttling.
+ */
+ suspend fun showErrorMessage() {
+ repository.setMessage(errorMessage(authenticationInteractor.getAuthenticationMethod()))
+ }
+
private fun promptMessage(authMethod: AuthenticationMethodModel): String {
return when (authMethod) {
is AuthenticationMethodModel.Pin ->
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index 0e0f1f6..579f0b7 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -79,14 +79,18 @@
) {
private val passiveAuthBouncerDelay =
context.resources.getInteger(R.integer.primary_bouncer_passive_auth_delay).toLong()
+
/** Runnable to show the primary bouncer. */
val showRunnable = Runnable {
repository.setPrimaryShow(true)
repository.setPrimaryShowingSoon(false)
primaryBouncerCallbackInteractor.dispatchVisibilityChanged(View.VISIBLE)
}
-
- val keyguardAuthenticated: Flow<Boolean> = repository.keyguardAuthenticated.filterNotNull()
+ val keyguardAuthenticatedPrimaryAuth: Flow<Int> = repository.keyguardAuthenticatedPrimaryAuth
+ val keyguardAuthenticatedBiometrics: Flow<Boolean> =
+ repository.keyguardAuthenticatedBiometrics.filterNotNull()
+ val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Int> =
+ repository.userRequestedBouncerWhenAlreadyAuthenticated.filterNotNull()
val isShowing: StateFlow<Boolean> = repository.primaryBouncerShow
val startingToHide: Flow<Unit> = repository.primaryBouncerStartingToHide.filter { it }.map {}
val isBackButtonEnabled: Flow<Boolean> = repository.isBackButtonEnabled.filterNotNull()
@@ -96,6 +100,7 @@
val resourceUpdateRequests: Flow<Boolean> = repository.resourceUpdateRequests.filter { it }
val keyguardPosition: Flow<Float> = repository.keyguardPosition.filterNotNull()
val panelExpansionAmount: Flow<Float> = repository.panelExpansionAmount
+
/** 0f = bouncer fully hidden. 1f = bouncer fully visible. */
val bouncerExpansion: Flow<Float> =
combine(repository.panelExpansionAmount, repository.primaryBouncerShow) {
@@ -107,6 +112,7 @@
0f
}
}
+
/** Allow for interaction when just about fully visible */
val isInteractable: Flow<Boolean> = bouncerExpansion.map { it > 0.9 }
val sideFpsShowing: Flow<Boolean> = repository.sideFpsShowing
@@ -144,7 +150,7 @@
@JvmOverloads
fun show(isScrimmed: Boolean) {
// Reset some states as we show the bouncer.
- repository.setKeyguardAuthenticated(null)
+ repository.setKeyguardAuthenticatedBiometrics(null)
repository.setPrimaryStartingToHide(false)
val resumeBouncer =
@@ -268,9 +274,19 @@
repository.setResourceUpdateRequests(true)
}
- /** Tell the bouncer that keyguard is authenticated. */
- fun notifyKeyguardAuthenticated(strongAuth: Boolean) {
- repository.setKeyguardAuthenticated(strongAuth)
+ /** Tell the bouncer that keyguard is authenticated with primary authentication. */
+ fun notifyKeyguardAuthenticatedPrimaryAuth(userId: Int) {
+ applicationScope.launch { repository.setKeyguardAuthenticatedPrimaryAuth(userId) }
+ }
+
+ /** Tell the bouncer that bouncer is requested when device is already authenticated */
+ fun notifyUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int) {
+ applicationScope.launch { repository.setKeyguardAuthenticatedPrimaryAuth(userId) }
+ }
+
+ /** Tell the bouncer that keyguard is authenticated with biometrics. */
+ fun notifyKeyguardAuthenticatedBiometrics(strongAuth: Boolean) {
+ repository.setKeyguardAuthenticatedBiometrics(strongAuth)
}
/** Update the position of the bouncer when showing. */
@@ -280,7 +296,7 @@
/** Notifies that the state change was handled. */
fun notifyKeyguardAuthenticatedHandled() {
- repository.setKeyguardAuthenticated(null)
+ repository.setKeyguardAuthenticatedBiometrics(null)
}
/** Notifies that the message was shown. */
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
index 6ba8439..649ae2f 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
@@ -59,7 +59,7 @@
val bouncerShowMessage: Flow<BouncerShowMessageModel> = interactor.showMessage
/** Observe whether keyguard is authenticated already. */
- val keyguardAuthenticated: Flow<Boolean> = interactor.keyguardAuthenticated
+ val keyguardAuthenticated: Flow<Boolean> = interactor.keyguardAuthenticatedBiometrics
/** Observe whether the side fps is showing. */
val sideFpsShowing: Flow<Boolean> = interactor.sideFpsShowing
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index 80a41ce..d214797 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -40,20 +40,21 @@
/** Notifies that the UI has been shown to the user. */
fun onShown() {
+ _password.value = ""
interactor.resetMessage()
}
/** Notifies that the user has changed the password input. */
- fun onPasswordInputChanged(password: String) {
- if (this.password.value.isEmpty() && password.isNotEmpty()) {
+ fun onPasswordInputChanged(newPassword: String) {
+ if (this.password.value.isEmpty() && newPassword.isNotEmpty()) {
interactor.clearMessage()
}
- if (password.isNotEmpty()) {
+ if (newPassword.isNotEmpty()) {
interactor.onIntentionalUserInput()
}
- _password.value = password
+ _password.value = newPassword
}
/** Notifies that the user has pressed the key for attempting to authenticate the password. */
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index 85eaf0b..364b5e7 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -170,7 +170,9 @@
_selectedDots.value = linkedSetOf()
applicationScope.launch {
- if (interactor.authenticate(pattern) != true) {
+ if (pattern.size < interactor.minPatternLength) {
+ interactor.showErrorMessage()
+ } else if (interactor.authenticate(pattern) != true) {
showFailureAnimation()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index ebf939b..dc5c528 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -70,13 +70,7 @@
/** Appearance of the confirm button. */
val confirmButtonAppearance: StateFlow<ActionButtonAppearance> =
interactor.isAutoConfirmEnabled
- .map {
- if (it) {
- ActionButtonAppearance.Hidden
- } else {
- ActionButtonAppearance.Shown
- }
- }
+ .map { if (it) ActionButtonAppearance.Hidden else ActionButtonAppearance.Shown }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
@@ -85,6 +79,7 @@
/** Notifies that the UI has been shown to the user. */
fun onShown() {
+ clearPinInput()
interactor.resetMessage()
}
@@ -113,7 +108,7 @@
/** Notifies that the user long-pressed the backspace button. */
fun onBackspaceButtonLongPressed() {
- mutablePinInput.value = mutablePinInput.value.clearAll()
+ clearPinInput()
}
/** Notifies that the user clicked the "enter" button. */
@@ -121,6 +116,10 @@
tryAuthenticate(useAutoConfirm = false)
}
+ private fun clearPinInput() {
+ mutablePinInput.value = mutablePinInput.value.clearAll()
+ }
+
private fun tryAuthenticate(useAutoConfirm: Boolean) {
val pinCode = mutablePinInput.value.getPin()
@@ -133,7 +132,7 @@
// TODO(b/291528545): this should not be cleared on success (at least until the view
// is animated away).
- mutablePinInput.value = mutablePinInput.value.clearAll()
+ clearPinInput()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 7ce7ce94..f12b919 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -34,9 +34,11 @@
import com.android.systemui.globalactions.GlobalActionsComponent
import com.android.systemui.keyboard.KeyboardUI
import com.android.systemui.keyboard.PhysicalKeyboardCoreStartable
-import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.KeyguardViewConfigurator
+import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.data.quickaffordance.MuteQuickAffordanceCoreStartable
+import com.android.systemui.keyguard.ui.binder.KeyguardDismissActionBinder
+import com.android.systemui.keyguard.ui.binder.KeyguardDismissBinder
import com.android.systemui.log.SessionTracker
import com.android.systemui.media.RingtonePlayer
import com.android.systemui.media.dialog.MediaOutputSwitcherDialogUI
@@ -74,12 +76,14 @@
/**
* Collection of {@link CoreStartable}s that should be run on AOSP.
*/
-@Module(includes = [
- MultiUserUtilsModule::class,
- StartControlsStartableModule::class,
- StartBinderLoggerModule::class,
- WallpaperModule::class,
-])
+@Module(
+ includes = [
+ MultiUserUtilsModule::class,
+ StartControlsStartableModule::class,
+ StartBinderLoggerModule::class,
+ WallpaperModule::class,
+ ]
+)
abstract class SystemUICoreStartableModule {
/** Inject into AuthController. */
@Binds
@@ -352,4 +356,14 @@
@IntoMap
@ClassKey(BackActionInteractor::class)
abstract fun bindBackActionInteractor(impl: BackActionInteractor): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(KeyguardDismissActionBinder::class)
+ abstract fun bindKeyguardDismissActionBinder(impl: KeyguardDismissActionBinder): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(KeyguardDismissBinder::class)
+ abstract fun bindKeyguardDismissBinder(impl: KeyguardDismissBinder): CoreStartable
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 55f703d..7e8f682 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -122,7 +122,7 @@
// TODO(b/292213543): Tracking Bug
@JvmField
val NOTIFICATION_GROUP_EXPANSION_CHANGE =
- unreleasedFlag("notification_group_expansion_change", teamfood = true)
+ unreleasedFlag("notification_group_expansion_change")
// 200 - keyguard/lockscreen
// ** Flag retired **
@@ -268,6 +268,10 @@
val MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA =
unreleasedFlag("migrate_split_keyguard_bottom_area", teamfood = true)
+ // TODO(b/297037052): Tracking bug.
+ @JvmField
+ val REMOVE_NPVC_BOTTOM_AREA_USAGE = unreleasedFlag("remove_npvc_bottom_area_usage")
+
/** Flag meant to guard the talkback fix for the KeyguardIndicationTextView */
// TODO(b/286563884): Tracking bug
@JvmField val KEYGUARD_TALKBACK_FIX = releasedFlag("keyguard_talkback_fix")
@@ -384,9 +388,6 @@
// TODO(b/265892345): Tracking Bug
val PLUG_IN_STATUS_BAR_CHIP = releasedFlag("plug_in_status_bar_chip")
- // TODO(b/280426085): Tracking Bug
- @JvmField val NEW_BLUETOOTH_REPOSITORY = releasedFlag("new_bluetooth_repository")
-
// TODO(b/292533677): Tracking Bug
val WIFI_TRACKER_LIB_FOR_WIFI_ICON = releasedFlag("wifi_tracker_lib_for_wifi_icon")
@@ -662,8 +663,6 @@
// TODO(b/259264861): Tracking Bug
@JvmField val UDFPS_NEW_TOUCH_DETECTION = releasedFlag("udfps_new_touch_detection")
@JvmField val UDFPS_ELLIPSE_DETECTION = releasedFlag("udfps_ellipse_detection")
- // TODO(b/278622168): Tracking Bug
- @JvmField val BIOMETRIC_BP_STRONG = releasedFlag("biometric_bp_strong")
// 2300 - stylus
@JvmField val TRACK_STYLUS_EVER_USED = releasedFlag("track_stylus_ever_used")
@@ -741,8 +740,7 @@
// 3000 - dream
// TODO(b/285059790) : Tracking Bug
@JvmField
- val LOCKSCREEN_WALLPAPER_DREAM_ENABLED =
- unreleasedFlag(name = "enable_lockscreen_wallpaper_dream", teamfood = true)
+ val LOCKSCREEN_WALLPAPER_DREAM_ENABLED = unreleasedFlag("enable_lockscreen_wallpaper_dream")
// TODO(b/283084712): Tracking Bug
@JvmField val IMPROVED_HUN_ANIMATIONS = unreleasedFlag("improved_hun_animations")
@@ -802,4 +800,8 @@
// TODO(b/287205379): Tracking bug
@JvmField
val QS_CONTAINER_GRAPH_OPTIMIZER = unreleasedFlag( "qs_container_graph_optimizer")
+
+ /** Enable showing a dialog when clicking on Quick Settings bluetooth tile. */
+ @JvmField
+ val BLUETOOTH_QS_TILE_DIALOG = unreleasedFlag("bluetooth_qs_tile_dialog")
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index d399e4c..2557e81 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -35,8 +35,10 @@
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
+import com.android.systemui.keyguard.shared.model.DismissAction
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
+import com.android.systemui.keyguard.shared.model.KeyguardDone
import com.android.systemui.keyguard.shared.model.KeyguardRootViewVisibilityState
import com.android.systemui.keyguard.shared.model.ScreenModel
import com.android.systemui.keyguard.shared.model.StatusBarState
@@ -53,9 +55,11 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
@@ -187,6 +191,12 @@
/** Receive an event for doze time tick */
val dozeTimeTick: Flow<Long>
+ /** Observable for DismissAction */
+ val dismissAction: StateFlow<DismissAction>
+
+ /** Observable updated when keyguardDone should be called either now or soon. */
+ val keyguardDone: Flow<KeyguardDone>
+
/**
* Returns `true` if the keyguard is showing; `false` otherwise.
*
@@ -239,6 +249,10 @@
fun setIsActiveDreamLockscreenHosted(isLockscreenHosted: Boolean)
fun dozeTimeTick()
+
+ fun setDismissAction(dismissAction: DismissAction)
+
+ suspend fun setKeyguardDone(keyguardDoneType: KeyguardDone)
}
/** Encapsulates application state for the keyguard. */
@@ -261,6 +275,19 @@
@Application private val scope: CoroutineScope,
private val systemClock: SystemClock,
) : KeyguardRepository {
+ private val _dismissAction: MutableStateFlow<DismissAction> =
+ MutableStateFlow(DismissAction.None)
+ override val dismissAction = _dismissAction.asStateFlow()
+ override fun setDismissAction(dismissAction: DismissAction) {
+ _dismissAction.value = dismissAction
+ }
+
+ private val _keyguardDone: MutableSharedFlow<KeyguardDone> = MutableSharedFlow()
+ override val keyguardDone = _keyguardDone.asSharedFlow()
+ override suspend fun setKeyguardDone(keyguardDoneType: KeyguardDone) {
+ _keyguardDone.emit(keyguardDoneType)
+ }
+
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions =
_animateBottomAreaDozingTransitions.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
index 867675b..00036ce 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data.repository
import android.app.trust.TrustManager
+import com.android.keyguard.TrustGrantFlags
import com.android.keyguard.logging.TrustRepositoryLogger
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -34,6 +35,7 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
@@ -50,6 +52,9 @@
/** Reports that whether trust is managed has changed for the current user. */
val isCurrentUserTrustManaged: StateFlow<Boolean>
+
+ /** A trust agent is requesting to dismiss the keyguard from a trust change. */
+ val trustAgentRequestingToDismissKeyguard: Flow<TrustModel>
}
@SysUISingleton
@@ -78,7 +83,7 @@
) {
logger.onTrustChanged(enabled, newlyUnlocked, userId, flags, grantMsgs)
trySendWithFailureLogging(
- TrustModel(enabled, userId),
+ TrustModel(enabled, userId, TrustGrantFlags(flags)),
TrustRepositoryLogger.TAG,
"onTrustChanged"
)
@@ -158,6 +163,17 @@
initialValue = false
)
+ override val trustAgentRequestingToDismissKeyguard: Flow<TrustModel>
+ get() =
+ combine(trust, userRepository.selectedUserInfo, ::Pair)
+ .map { latestTrustModelForUser[it.second.id] }
+ .distinctUntilChanged()
+ .filter {
+ it != null &&
+ (it.flags.isInitiatedByUser || it.flags.dismissKeyguardRequested())
+ }
+ .map { it!! }
+
private fun isUserTrustManaged(userId: Int) =
trustManagedForUser[userId]?.isTrustManaged ?: false
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
new file mode 100644
index 0000000..08d29d4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.keyguard.shared.model.DismissAction
+import com.android.systemui.keyguard.shared.model.KeyguardDone
+import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNot
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.stateIn
+
+/** Encapsulates business-logic for actions to run when the keyguard is dismissed. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class KeyguardDismissActionInteractor
+@Inject
+constructor(
+ private val repository: KeyguardRepository,
+ transitionInteractor: KeyguardTransitionInteractor,
+ val dismissInteractor: KeyguardDismissInteractor,
+ @Application private val applicationScope: CoroutineScope,
+) {
+ val dismissAction: Flow<DismissAction> = repository.dismissAction
+
+ val onCancel: Flow<Runnable> = dismissAction.map { it.onCancelAction }
+
+ // TODO (b/268240415): use message in alt + primary bouncer message
+ // message to show to the user about the dismiss action, else empty string
+ val message = dismissAction.map { it.message }
+
+ /**
+ * True if the dismiss action will run an animation on the lockscreen and requires any views
+ * that would obscure this animation (ie: the primary bouncer) to immediately hide, so the
+ * animation would be visible.
+ */
+ val willAnimateDismissActionOnLockscreen: StateFlow<Boolean> =
+ dismissAction
+ .map { it.willAnimateOnLockscreen }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
+
+ private val finishedTransitionToGone: Flow<Unit> =
+ transitionInteractor.finishedKeyguardState.filter { it == GONE }.map {} // map to Unit
+ val executeDismissAction: Flow<() -> KeyguardDone> =
+ merge(
+ finishedTransitionToGone,
+ dismissInteractor.dismissKeyguardRequestWithImmediateDismissAction
+ )
+ .sample(dismissAction)
+ .filterNot { it is DismissAction.None }
+ .map { it.onDismissAction }
+ val resetDismissAction: Flow<Unit> =
+ transitionInteractor.finishedKeyguardTransitionStep
+ .filter { it.to != ALTERNATE_BOUNCER && it.to != PRIMARY_BOUNCER && it.to != GONE }
+ .sample(dismissAction)
+ .filterNot { it is DismissAction.None }
+ .map {} // map to Unit
+
+ fun runDismissAnimationOnKeyguard(): Boolean {
+ return willAnimateDismissActionOnLockscreen.value
+ }
+
+ fun runAfterKeyguardGone(runnable: Runnable) {
+ setDismissAction(
+ DismissAction.RunAfterKeyguardGone(
+ dismissAction = { runnable.run() },
+ onCancelAction = {},
+ message = "",
+ willAnimateOnLockscreen = false,
+ )
+ )
+ }
+
+ fun setDismissAction(dismissAction: DismissAction) {
+ repository.dismissAction.value.onCancelAction.run()
+ repository.setDismissAction(dismissAction)
+ }
+
+ fun handleDismissAction() {
+ repository.setDismissAction(DismissAction.None)
+ }
+
+ suspend fun setKeyguardDone(keyguardDoneTiming: KeyguardDone) {
+ dismissInteractor.setKeyguardDone(keyguardDoneTiming)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt
new file mode 100644
index 0000000..cab6928
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.keyguard.data.repository.TrustRepository
+import com.android.systemui.keyguard.shared.model.DismissAction
+import com.android.systemui.keyguard.shared.model.KeyguardDone
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.util.kotlin.Utils.Companion.toQuad
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+/** Encapsulates business logic for requesting the keyguard to dismiss/finish/done. */
+@SysUISingleton
+class KeyguardDismissInteractor
+@Inject
+constructor(
+ trustRepository: TrustRepository,
+ val keyguardRepository: KeyguardRepository,
+ val primaryBouncerInteractor: PrimaryBouncerInteractor,
+ val alternateBouncerInteractor: AlternateBouncerInteractor,
+ val powerInteractor: PowerInteractor,
+ val userInteractor: UserInteractor,
+) {
+ /*
+ * Updates when a biometric has authenticated the device and is requesting to dismiss
+ * the keyguard. When true, a class 3 biometrics has authenticated. Else, a lower class
+ * biometric strength has authenticated and is requesting to dismiss the keyguard.
+ */
+ private val biometricAuthenticatedRequestDismissKeyguard: Flow<Unit> =
+ primaryBouncerInteractor.keyguardAuthenticatedBiometrics.map {} // map to Unit
+
+ /*
+ * Updates when a trust change is requesting to dismiss the keyguard and is able to do so
+ * in the current device state.
+ */
+ private val onTrustGrantedRequestDismissKeyguard: Flow<Unit> =
+ trustRepository.trustAgentRequestingToDismissKeyguard
+ .sample(
+ combine(
+ primaryBouncerInteractor.isShowing,
+ alternateBouncerInteractor.isVisible,
+ powerInteractor.isInteractive,
+ ::Triple
+ ),
+ ::toQuad
+ )
+ .filter { (trustModel, primaryBouncerShowing, altBouncerShowing, interactive) ->
+ val bouncerShowing = primaryBouncerShowing || altBouncerShowing
+ (interactive || trustModel.flags.temporaryAndRenewable()) &&
+ (bouncerShowing || trustModel.flags.dismissKeyguardRequested())
+ }
+ .map {} // map to Unit
+
+ /*
+ * Updates when the current user successfully has authenticated via primary authentication
+ * (pin/pattern/password).
+ */
+ private val primaryAuthenticated: Flow<Unit> =
+ primaryBouncerInteractor.keyguardAuthenticatedPrimaryAuth
+ .filter { authedUserId -> authedUserId == userInteractor.getSelectedUserId() }
+ .map {} // map to Unit
+
+ /*
+ * Updates when the current user requests the bouncer after they've already successfully
+ * authenticated (ie: from non-bypass face auth, from a trust agent that didn't immediately
+ * dismiss the keyguard, or if keyguard security is set to SWIPE or NONE).
+ */
+ private val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Unit> =
+ primaryBouncerInteractor.userRequestedBouncerWhenAlreadyAuthenticated
+ .filter { authedUserId -> authedUserId == userInteractor.getSelectedUserId() }
+ .map {} // map to Unit
+
+ /** Updates when keyguardDone should be requested. */
+ val keyguardDone: Flow<KeyguardDone> = keyguardRepository.keyguardDone
+
+ /** Updates when any request to dismiss the current user's keyguard has arrived. */
+ private val dismissKeyguardRequest: Flow<DismissAction> =
+ merge(
+ biometricAuthenticatedRequestDismissKeyguard,
+ onTrustGrantedRequestDismissKeyguard,
+ primaryAuthenticated,
+ userRequestedBouncerWhenAlreadyAuthenticated,
+ )
+ .sample(keyguardRepository.dismissAction)
+
+ /**
+ * Updates when a request to dismiss the current user's keyguard has arrived and there's a
+ * dismiss action to run immediately. It's expected that the consumer will request keyguardDone
+ * with or without a deferral.
+ */
+ val dismissKeyguardRequestWithImmediateDismissAction: Flow<Unit> =
+ dismissKeyguardRequest.filter { it is DismissAction.RunImmediately }.map {} // map to Unit
+
+ /**
+ * Updates when a request to dismiss the current user's keyguard has arrived and there's isn't a
+ * dismiss action to run immediately. There may still be a dismiss action to run after the
+ * keyguard transitions to GONE.
+ */
+ val dismissKeyguardRequestWithoutImmediateDismissAction: Flow<Unit> =
+ dismissKeyguardRequest.filter { it !is DismissAction.RunImmediately }.map {} // map to Unit
+
+ suspend fun setKeyguardDone(keyguardDoneTiming: KeyguardDone) {
+ keyguardRepository.setKeyguardDone(keyguardDoneTiming)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/DismissAction.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/DismissAction.kt
new file mode 100644
index 0000000..c8d5599
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/DismissAction.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.shared.model
+
+/** DismissAction models */
+sealed interface DismissAction {
+ val onDismissAction: () -> KeyguardDone
+ val onCancelAction: Runnable
+ val message: String
+ /**
+ * True if the dismiss action will run an animation on the keyguard and requires any views that
+ * would obscure this animation (ie: the primary bouncer) to immediately hide, so the animation
+ * would be visible.
+ */
+ val willAnimateOnLockscreen: Boolean
+ val runAfterKeyguardGone: Boolean
+
+ class RunImmediately(
+ override val onDismissAction: () -> KeyguardDone,
+ override val onCancelAction: Runnable,
+ override val message: String,
+ override val willAnimateOnLockscreen: Boolean,
+ ) : DismissAction {
+ override val runAfterKeyguardGone: Boolean = false
+ }
+
+ class RunAfterKeyguardGone(
+ val dismissAction: () -> Unit,
+ override val onCancelAction: Runnable,
+ override val message: String,
+ override val willAnimateOnLockscreen: Boolean,
+ ) : DismissAction {
+ override val onDismissAction: () -> KeyguardDone = {
+ dismissAction()
+ // no-op, when this dismissAction is run after the keyguard is gone,
+ // the keyguard is already done so KeyguardDone timing is irrelevant
+ KeyguardDone.IMMEDIATE
+ }
+ override val runAfterKeyguardGone: Boolean = true
+ }
+
+ data object None : DismissAction {
+ override val onDismissAction: () -> KeyguardDone = { KeyguardDone.IMMEDIATE }
+ override val onCancelAction: Runnable = Runnable {}
+ override val message: String = ""
+ override val willAnimateOnLockscreen: Boolean = false
+ override val runAfterKeyguardGone: Boolean = false
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardDone.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardDone.kt
new file mode 100644
index 0000000..5e8cf57
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardDone.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.shared.model
+
+/**
+ * When to send the keyguard done signal. Should it immediately be sent when the keyguard is
+ * requested to be dismissed? Or should it be sent later?
+ */
+enum class KeyguardDone {
+ IMMEDIATE, // keyguard is immediately done, immediately start transitioning away keyguard
+ LATER, // keyguard is dismissible pending the next keyguardDone call
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TrustModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TrustModel.kt
index cdfab1a..206b792 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TrustModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TrustModel.kt
@@ -16,6 +16,8 @@
package com.android.systemui.keyguard.shared.model
+import com.android.keyguard.TrustGrantFlags
+
sealed class TrustMessage
/** Represents the trust state */
@@ -24,6 +26,7 @@
val isTrusted: Boolean,
/** The user, for which the trust changed. */
val userId: Int,
+ val flags: TrustGrantFlags,
) : TrustMessage()
/** Represents where trust agents are enabled for a particular user. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
index a8070c2..3dd3e07 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
@@ -18,11 +18,13 @@
package com.android.systemui.keyguard.ui.binder
import android.os.Trace
+import android.transition.TransitionManager
import android.util.Log
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.BaseBlueprintTransition
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import kotlinx.coroutines.launch
@@ -40,17 +42,29 @@
Trace.beginSection("KeyguardBlueprint#applyBlueprint")
Log.d(TAG, "applying blueprint: $blueprint")
- ConstraintSet().apply {
- clone(constraintLayout)
- val emptyLayout = ConstraintSet.Layout()
- knownIds.forEach { getConstraint(it).layout.copyFrom(emptyLayout) }
- blueprint.applyConstraints(this)
- // Add and remove views of sections that are not contained by the
- // other.
- blueprint?.replaceViews(prevBluePrint, constraintLayout)
- applyTo(constraintLayout)
+ val cs =
+ ConstraintSet().apply {
+ clone(constraintLayout)
+ val emptyLayout = ConstraintSet.Layout()
+ knownIds.forEach {
+ getConstraint(it).layout.copyFrom(emptyLayout)
+ }
+ blueprint.applyConstraints(this)
+ }
+
+ // Apply transition.
+ if (prevBluePrint != null && prevBluePrint != blueprint) {
+ TransitionManager.beginDelayedTransition(
+ constraintLayout,
+ BaseBlueprintTransition()
+ )
}
+ // Add and remove views of sections that are not contained by the
+ // other.
+ blueprint.replaceViews(prevBluePrint, constraintLayout)
+ cs.applyTo(constraintLayout)
+
viewModel.currentBluePrint = blueprint
Trace.endSection()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt
new file mode 100644
index 0000000..d5add61
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.keyguard.ui.binder
+
+import com.android.keyguard.logging.KeyguardLogger
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
+
+/** Runs actions on keyguard dismissal. */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class KeyguardDismissActionBinder
+@Inject
+constructor(
+ private val interactor: KeyguardDismissActionInteractor,
+ @Application private val scope: CoroutineScope,
+ private val keyguardLogger: KeyguardLogger,
+ private val featureFlags: FeatureFlagsClassic,
+) : CoreStartable {
+
+ override fun start() {
+ if (!featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ return
+ }
+
+ scope.launch {
+ interactor.executeDismissAction.collect {
+ log("executeDismissAction")
+ interactor.setKeyguardDone(it())
+ interactor.handleDismissAction()
+ }
+ }
+
+ scope.launch {
+ interactor.resetDismissAction.sample(interactor.onCancel).collect {
+ log("resetDismissAction")
+ it.run()
+ interactor.handleDismissAction()
+ }
+ }
+
+ scope.launch { interactor.dismissAction.collect { log("updatedDismissAction=$it") } }
+ }
+
+ private fun log(message: String) {
+ keyguardLogger.log(TAG, LogLevel.DEBUG, message)
+ }
+
+ companion object {
+ private const val TAG = "KeyguardDismissAction"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt
new file mode 100644
index 0000000..f14552b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.keyguard.ui.binder
+
+import com.android.keyguard.ViewMediatorCallback
+import com.android.keyguard.logging.KeyguardLogger
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardDone
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.user.domain.interactor.UserInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
+
+/** Handles keyguard dismissal requests. */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class KeyguardDismissBinder
+@Inject
+constructor(
+ private val interactor: KeyguardDismissInteractor,
+ private val userInteractor: UserInteractor,
+ private val viewMediatorCallback: ViewMediatorCallback,
+ @Application private val scope: CoroutineScope,
+ private val keyguardLogger: KeyguardLogger,
+ private val featureFlags: FeatureFlagsClassic,
+) : CoreStartable {
+
+ override fun start() {
+ if (!featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ return
+ }
+
+ scope.launch {
+ interactor.keyguardDone.collect { keyguardDoneTiming ->
+ when (keyguardDoneTiming) {
+ KeyguardDone.LATER -> {
+ log("keyguardDonePending")
+ viewMediatorCallback.keyguardDonePending(userInteractor.getSelectedUserId())
+ }
+ else -> {
+ log("keyguardDone")
+ viewMediatorCallback.keyguardDone(userInteractor.getSelectedUserId())
+ }
+ }
+ }
+ }
+
+ scope.launch {
+ interactor.dismissKeyguardRequestWithoutImmediateDismissAction.collect {
+ log("dismissKeyguardRequestWithoutImmediateDismissAction-keyguardDone")
+ interactor.setKeyguardDone(KeyguardDone.IMMEDIATE)
+ }
+ }
+ }
+
+ private fun log(message: String) {
+ keyguardLogger.log(TAG, LogLevel.DEBUG, message)
+ }
+
+ companion object {
+ private const val TAG = "KeyguardDismiss"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt
new file mode 100644
index 0000000..42b1c10
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/BaseBlueprintTransition.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.blueprints.transitions
+
+import android.animation.Animator
+import android.animation.ObjectAnimator
+import android.transition.ChangeBounds
+import android.transition.TransitionSet
+import android.transition.TransitionValues
+import android.transition.Visibility
+import android.view.View
+import android.view.ViewGroup
+
+class BaseBlueprintTransition : TransitionSet() {
+ init {
+ ordering = ORDERING_SEQUENTIAL
+ addTransition(AlphaOutVisibility())
+ .addTransition(ChangeBounds())
+ .addTransition(AlphaInVisibility())
+ }
+ class AlphaOutVisibility : Visibility() {
+ override fun onDisappear(
+ sceneRoot: ViewGroup?,
+ view: View,
+ startValues: TransitionValues?,
+ endValues: TransitionValues?
+ ): Animator {
+ return ObjectAnimator.ofFloat(view, "alpha", 0f).apply {
+ addUpdateListener { view.alpha = it.animatedValue as Float }
+ start()
+ }
+ }
+ }
+
+ class AlphaInVisibility : Visibility() {
+ override fun onAppear(
+ sceneRoot: ViewGroup?,
+ view: View,
+ startValues: TransitionValues?,
+ endValues: TransitionValues?
+ ): Animator {
+ return ObjectAnimator.ofFloat(view, "alpha", 1f).apply {
+ addUpdateListener { view.alpha = it.animatedValue as Float }
+ start()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index cca96b7..0783181 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -19,27 +19,36 @@
import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.ScrimAlpha
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.statusbar.SysuiStatusBarStateController
+import dagger.Lazy
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
/**
* Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to
* consume.
*/
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class PrimaryBouncerToGoneTransitionViewModel
@Inject
constructor(
- private val interactor: KeyguardTransitionInteractor,
+ interactor: KeyguardTransitionInteractor,
private val statusBarStateController: SysuiStatusBarStateController,
private val primaryBouncerInteractor: PrimaryBouncerInteractor,
+ keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>,
+ featureFlags: FeatureFlagsClassic,
) {
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
@@ -52,11 +61,18 @@
/** Bouncer container alpha */
val bouncerAlpha: Flow<Float> =
- transitionAnimation.createFlow(
+ if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ keyguardDismissActionInteractor
+ .get()
+ .willAnimateDismissActionOnLockscreen
+ .flatMapLatest { createBouncerAlphaFlow { it } }
+ } else {
+ createBouncerAlphaFlow(primaryBouncerInteractor::willRunDismissFromKeyguard)
+ }
+ private fun createBouncerAlphaFlow(willRunAnimationOnKeyguard: () -> Boolean): Flow<Float> {
+ return transitionAnimation.createFlow(
duration = 200.milliseconds,
- onStart = {
- willRunDismissFromKeyguard = primaryBouncerInteractor.willRunDismissFromKeyguard()
- },
+ onStart = { willRunDismissFromKeyguard = willRunAnimationOnKeyguard() },
onStep = {
if (willRunDismissFromKeyguard) {
0f
@@ -65,14 +81,24 @@
}
},
)
+ }
/** Lockscreen alpha */
val lockscreenAlpha: Flow<Float> =
- transitionAnimation.createFlow(
+ if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ keyguardDismissActionInteractor
+ .get()
+ .willAnimateDismissActionOnLockscreen
+ .flatMapLatest { createLockscreenAlpha { it } }
+ } else {
+ createLockscreenAlpha(primaryBouncerInteractor::willRunDismissFromKeyguard)
+ }
+ private fun createLockscreenAlpha(willRunAnimationOnKeyguard: () -> Boolean): Flow<Float> {
+ return transitionAnimation.createFlow(
duration = 50.milliseconds,
onStart = {
leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
- willRunDismissFromKeyguard = primaryBouncerInteractor.willRunDismissFromKeyguard()
+ willRunDismissFromKeyguard = willRunAnimationOnKeyguard()
},
onStep = {
if (willRunDismissFromKeyguard || leaveShadeOpen) {
@@ -82,17 +108,26 @@
}
},
)
+ }
/** Scrim alpha values */
val scrimAlpha: Flow<ScrimAlpha> =
- transitionAnimation
+ if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ keyguardDismissActionInteractor
+ .get()
+ .willAnimateDismissActionOnLockscreen
+ .flatMapLatest { createScrimAlphaFlow { it } }
+ } else {
+ createScrimAlphaFlow(primaryBouncerInteractor::willRunDismissFromKeyguard)
+ }
+ private fun createScrimAlphaFlow(willRunAnimationOnKeyguard: () -> Boolean): Flow<ScrimAlpha> {
+ return transitionAnimation
.createFlow(
duration = TO_GONE_DURATION,
interpolator = EMPHASIZED_ACCELERATE,
onStart = {
leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()
- willRunDismissFromKeyguard =
- primaryBouncerInteractor.willRunDismissFromKeyguard()
+ willRunDismissFromKeyguard = willRunAnimationOnKeyguard()
},
onStep = { 1f - it },
)
@@ -108,4 +143,5 @@
ScrimAlpha(behindAlpha = it)
}
}
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index 053c9b5..60fd104 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -29,7 +29,10 @@
import android.os.IBinder
import android.os.ResultReceiver
import android.os.UserHandle
+import android.util.Log
+import android.view.View
import android.view.ViewGroup
+import android.view.accessibility.AccessibilityEvent
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
@@ -40,6 +43,9 @@
import com.android.internal.app.ResolverListController
import com.android.internal.app.chooser.NotSelectableTargetInfo
import com.android.internal.app.chooser.TargetInfo
+import com.android.internal.widget.RecyclerView
+import com.android.internal.widget.RecyclerViewAccessibilityDelegate
+import com.android.internal.widget.ResolverDrawerLayout
import com.android.systemui.R
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorComponent
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorController
@@ -105,6 +111,10 @@
super.onCreate(bundle)
controller.init()
+ // we override AppList's AccessibilityDelegate set in ResolverActivity.onCreate because in
+ // our case this delegate must extend RecyclerViewAccessibilityDelegate, otherwise
+ // RecyclerView scrolling is broken
+ setAppListAccessibilityDelegate()
}
override fun onStart() {
@@ -277,6 +287,8 @@
recentsViewController.createView(parent)
companion object {
+ const val TAG = "MediaProjectionAppSelectorActivity"
+
/**
* When EXTRA_CAPTURE_REGION_RESULT_RECEIVER is passed as intent extra the activity will
* send the [CaptureRegion] to the result receiver instead of returning media projection
@@ -313,4 +325,42 @@
putExtra(EXTRA_SELECTED_PROFILE, selectedProfile)
}
}
+
+ private fun setAppListAccessibilityDelegate() {
+ val rdl = requireViewById<ResolverDrawerLayout>(com.android.internal.R.id.contentPanel)
+ for (i in 0 until mMultiProfilePagerAdapter.count) {
+ val list =
+ mMultiProfilePagerAdapter
+ .getItem(i)
+ .rootView
+ .findViewById<View>(com.android.internal.R.id.resolver_list)
+ if (list == null || list !is RecyclerView) {
+ Log.wtf(TAG, "MediaProjection only supports RecyclerView")
+ } else {
+ list.accessibilityDelegate = RecyclerViewExpandingAccessibilityDelegate(rdl, list)
+ }
+ }
+ }
+
+ /**
+ * An a11y delegate propagating all a11y events to [AppListAccessibilityDelegate] so that it can
+ * expand drawer when needed. It needs to extend [RecyclerViewAccessibilityDelegate] because
+ * that superclass handles RecyclerView scrolling while using a11y services.
+ */
+ private class RecyclerViewExpandingAccessibilityDelegate(
+ rdl: ResolverDrawerLayout,
+ view: RecyclerView
+ ) : RecyclerViewAccessibilityDelegate(view) {
+
+ private val delegate = AppListAccessibilityDelegate(rdl)
+
+ override fun onRequestSendAccessibilityEvent(
+ host: ViewGroup,
+ child: View,
+ event: AccessibilityEvent
+ ): Boolean {
+ super.onRequestSendAccessibilityEvent(host, child, event)
+ return delegate.onRequestSendAccessibilityEvent(host, child, event)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 555269d..62b22c5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -133,7 +133,6 @@
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.systemui.shared.recents.utilities.Utilities;
@@ -156,6 +155,7 @@
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.ViewController;
import com.android.wm.shell.back.BackAnimation;
@@ -200,7 +200,7 @@
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final SysUiState mSysUiFlagsContainer;
private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
- private final ShadeController mShadeController;
+ private final KeyguardStateController mKeyguardStateController;
private final ShadeViewController mShadeViewController;
private final NotificationRemoteInputManager mNotificationRemoteInputManager;
private final OverviewProxyService mOverviewProxyService;
@@ -262,7 +262,7 @@
@VisibleForTesting
public int mDisplayId;
private boolean mIsOnDefaultDisplay;
- public boolean mHomeBlockedThisTouch;
+ private boolean mHomeBlockedThisTouch;
/**
* When user is QuickSwitching between apps of different orientations, we'll draw a fake
@@ -531,7 +531,6 @@
@Inject
NavigationBar(
NavigationBarView navigationBarView,
- ShadeController shadeController,
NavigationBarFrame navigationBarFrame,
@Nullable Bundle savedState,
@DisplayId Context context,
@@ -550,6 +549,7 @@
Optional<Pip> pipOptional,
Optional<Recents> recentsOptional,
Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
+ KeyguardStateController keyguardStateController,
ShadeViewController shadeViewController,
NotificationRemoteInputManager notificationRemoteInputManager,
NotificationShadeDepthController notificationShadeDepthController,
@@ -585,7 +585,7 @@
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mSysUiFlagsContainer = sysUiFlagsContainer;
mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
- mShadeController = shadeController;
+ mKeyguardStateController = keyguardStateController;
mShadeViewController = shadeViewController;
mNotificationRemoteInputManager = notificationRemoteInputManager;
mOverviewProxyService = overviewProxyService;
@@ -1326,8 +1326,7 @@
mHomeBlockedThisTouch = false;
if (mTelecomManagerOptional.isPresent()
&& mTelecomManagerOptional.get().isRinging()) {
- if (centralSurfacesOptional.map(CentralSurfaces::isKeyguardShowing)
- .orElse(false)) {
+ if (mKeyguardStateController.isShowing()) {
Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " +
"No heads up");
mHomeBlockedThisTouch = true;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 580facd..5a42028 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -19,7 +19,6 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
-
import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG;
import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen;
@@ -58,7 +57,6 @@
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
import com.android.systemui.statusbar.phone.LightBarController;
@@ -75,7 +73,6 @@
/** A controller to handle navigation bars. */
@SysUISingleton
public class NavigationBarController implements
- Callbacks,
ConfigurationController.ConfigurationListener,
NavigationModeController.ModeChangedListener,
Dumpable {
@@ -130,7 +127,7 @@
mSecureSettings = secureSettings;
mDisplayTracker = displayTracker;
mDisplayManager = mContext.getSystemService(DisplayManager.class);
- commandQueue.addCallback(this);
+ commandQueue.addCallback(mCommandQueueCallbacks);
configurationController.addCallback(this);
mConfigChanges.applyNewConfig(mContext.getResources());
mNavMode = navigationModeController.addListener(this);
@@ -270,25 +267,51 @@
return taskbarEnabled;
}
- @Override
- public void onDisplayRemoved(int displayId) {
- removeNavigationBar(displayId);
- }
-
- @Override
- public void onDisplayReady(int displayId) {
- Display display = mDisplayManager.getDisplay(displayId);
- mIsLargeScreen = isLargeScreen(mContext);
- createNavigationBar(display, null /* savedState */, null /* result */);
- }
-
- @Override
- public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
- final NavigationBar navigationBar = getNavigationBar(displayId);
- if (navigationBar != null) {
- navigationBar.setNavigationBarLumaSamplingEnabled(enable);
+ private final CommandQueue.Callbacks mCommandQueueCallbacks = new CommandQueue.Callbacks() {
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ removeNavigationBar(displayId);
}
- }
+
+ @Override
+ public void onDisplayReady(int displayId) {
+ Display display = mDisplayManager.getDisplay(displayId);
+ mIsLargeScreen = isLargeScreen(mContext);
+ createNavigationBar(display, null /* savedState */, null /* result */);
+ }
+
+ @Override
+ public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+ final NavigationBar navigationBar = getNavigationBar(displayId);
+ if (navigationBar != null) {
+ navigationBar.setNavigationBarLumaSamplingEnabled(enable);
+ }
+ }
+
+ @Override
+ public void showPinningEnterExitToast(boolean entering) {
+ int displayId = mContext.getDisplayId();
+ final NavigationBarView navBarView = getNavigationBarView(displayId);
+ if (navBarView != null) {
+ navBarView.showPinningEnterExitToast(entering);
+ } else if (displayId == mDisplayTracker.getDefaultDisplayId()
+ && mTaskbarDelegate.isInitialized()) {
+ mTaskbarDelegate.showPinningEnterExitToast(entering);
+ }
+ }
+
+ @Override
+ public void showPinningEscapeToast() {
+ int displayId = mContext.getDisplayId();
+ final NavigationBarView navBarView = getNavigationBarView(displayId);
+ if (navBarView != null) {
+ navBarView.showPinningEscapeToast();
+ } else if (displayId == mDisplayTracker.getDefaultDisplayId()
+ && mTaskbarDelegate.isInitialized()) {
+ mTaskbarDelegate.showPinningEscapeToast();
+ }
+ }
+ };
/**
* Recreates the navigation bar for the given display.
@@ -446,26 +469,6 @@
return mNavigationBars.get(displayId);
}
- public void showPinningEnterExitToast(int displayId, boolean entering) {
- final NavigationBarView navBarView = getNavigationBarView(displayId);
- if (navBarView != null) {
- navBarView.showPinningEnterExitToast(entering);
- } else if (displayId == mDisplayTracker.getDefaultDisplayId()
- && mTaskbarDelegate.isInitialized()) {
- mTaskbarDelegate.showPinningEnterExitToast(entering);
- }
- }
-
- public void showPinningEscapeToast(int displayId) {
- final NavigationBarView navBarView = getNavigationBarView(displayId);
- if (navBarView != null) {
- navBarView.showPinningEscapeToast();
- } else if (displayId == mDisplayTracker.getDefaultDisplayId()
- && mTaskbarDelegate.isInitialized()) {
- mTaskbarDelegate.showPinningEscapeToast();
- }
- }
-
public boolean isOverviewEnabled(int displayId) {
final NavigationBarView navBarView = getNavigationBarView(displayId);
if (navBarView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 4b22edc..21c5ae8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -16,7 +16,6 @@
package com.android.systemui.recents;
-import android.annotation.Nullable;
import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
@@ -25,11 +24,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.shared.recents.IOverviewProxy;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
-
-import dagger.Lazy;
-
-import java.util.Optional;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import javax.inject.Inject;
@@ -40,20 +35,20 @@
public class OverviewProxyRecentsImpl implements RecentsImplementation {
private final static String TAG = "OverviewProxyRecentsImpl";
- @Nullable
- private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
-
private Handler mHandler;
private final OverviewProxyService mOverviewProxyService;
private final ActivityStarter mActivityStarter;
+ private final KeyguardStateController mKeyguardStateController;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
- public OverviewProxyRecentsImpl(Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
- OverviewProxyService overviewProxyService, ActivityStarter activityStarter) {
- mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
+ public OverviewProxyRecentsImpl(
+ OverviewProxyService overviewProxyService,
+ ActivityStarter activityStarter,
+ KeyguardStateController keyguardStateController) {
mOverviewProxyService = overviewProxyService;
mActivityStarter = activityStarter;
+ mKeyguardStateController = keyguardStateController;
}
@Override
@@ -101,9 +96,7 @@
}
};
// Preload only if device for current user is unlocked
- final Optional<CentralSurfaces> centralSurfacesOptional =
- mCentralSurfacesOptionalLazy.get();
- if (centralSurfacesOptional.map(CentralSurfaces::isKeyguardShowing).orElse(false)) {
+ if (mKeyguardStateController.isShowing()) {
mActivityStarter.executeRunnableDismissingKeyguard(
() -> mHandler.post(toggleRecents), null, true /* dismissShade */,
false /* afterKeyguardGone */,
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
index 83fb723..291d273 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -69,7 +69,9 @@
listOf(ComposeMustBeAvailable(), CompileTimeFlagMustBeEnabled())
override fun isEnabled(): Boolean {
- return requirements.all { it.isMet() }
+ // SCENE_CONTAINER_ENABLED is an explicit static flag check that helps with downstream
+ // optimizations, e.g., unused code stripping. Do not remove!
+ return Flags.SCENE_CONTAINER_ENABLED && requirements.all { it.isMet() }
}
override fun requirementDescription(): String {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 246ea0e..49ce832 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -97,6 +97,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.SystemBarUtils;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.ActiveUnlockConfig;
import com.android.keyguard.FaceAuthApiRequestReason;
@@ -165,7 +166,6 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.shade.data.repository.ShadeRepository;
import com.android.systemui.shade.transition.ShadeTransitionController;
-import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.GestureRecorder;
@@ -336,6 +336,7 @@
private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
private final FragmentService mFragmentService;
+ private final IStatusBarService mStatusBarService;
private final ScrimController mScrimController;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final TapAgainViewController mTapAgainViewController;
@@ -370,7 +371,6 @@
/** The current squish amount for the predictive back animation */
private float mCurrentBackProgress = 0.0f;
private boolean mTracking;
- private boolean mIsTrackingExpansionFromStatusBar;
private boolean mHintAnimationRunning;
@Deprecated
private KeyguardBottomAreaView mKeyguardBottomArea;
@@ -744,6 +744,7 @@
NavigationBarController navigationBarController,
QuickSettingsController quickSettingsController,
FragmentService fragmentService,
+ IStatusBarService statusBarService,
ContentResolver contentResolver,
ShadeHeaderController shadeHeaderController,
ScreenOffAnimationController screenOffAnimationController,
@@ -874,6 +875,7 @@
mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
mFragmentService = fragmentService;
+ mStatusBarService = statusBarService;
mSettingsChangeObserver = new SettingsChangeObserver(handler);
mSplitShadeEnabled =
LargeScreenUtils.shouldUseSplitNotificationShade(mResources);
@@ -2845,7 +2847,6 @@
private void onTrackingStopped(boolean expand) {
mTracking = false;
- maybeStopTrackingExpansionFromStatusBar(expand);
updateExpansionAndVisibility();
if (expand) {
@@ -3036,7 +3037,9 @@
private void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
mHeadsUpManager = headsUpManager;
mHeadsUpManager.addListener(mOnHeadsUpChangedListener);
- mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager,
+ mHeadsUpTouchHelper = new HeadsUpTouchHelper(
+ headsUpManager,
+ mStatusBarService,
mNotificationStackScrollLayoutController.getHeadsUpCallback(),
new HeadsUpNotificationViewControllerImpl());
}
@@ -4244,42 +4247,6 @@
}
@Override
- public void startTrackingExpansionFromStatusBar() {
- mIsTrackingExpansionFromStatusBar = true;
- InteractionJankMonitorWrapper.begin(
- mView, InteractionJankMonitorWrapper.CUJ_SHADE_EXPAND_FROM_STATUS_BAR);
- }
-
- /**
- * Stops tracking an expansion that originated from the status bar (if we had started tracking
- * it).
- *
- * @param expand the expand boolean passed to {@link #onTrackingStopped(boolean)}.
- */
- private void maybeStopTrackingExpansionFromStatusBar(boolean expand) {
- if (!mIsTrackingExpansionFromStatusBar) {
- return;
- }
- mIsTrackingExpansionFromStatusBar = false;
-
- // Determine whether the shade actually expanded due to the status bar touch:
- // - If the user just taps on the status bar, then #isExpanded is false but
- // #onTrackingStopped is called with `true`.
- // - If the user drags down on the status bar but doesn't drag down far enough, then
- // #onTrackingStopped is called with `false` but #isExpanded is true.
- // So, we need *both* #onTrackingStopped called with `true` *and* #isExpanded to be true in
- // order to confirm that the shade successfully opened.
- boolean shadeExpansionFromStatusBarSucceeded = expand && isExpanded();
- if (shadeExpansionFromStatusBarSucceeded) {
- InteractionJankMonitorWrapper.end(
- InteractionJankMonitorWrapper.CUJ_SHADE_EXPAND_FROM_STATUS_BAR);
- } else {
- InteractionJankMonitorWrapper.cancel(
- InteractionJankMonitorWrapper.CUJ_SHADE_EXPAND_FROM_STATUS_BAR);
- }
- }
-
- @Override
public void updateTouchableRegion() {
//A layout will ensure that onComputeInternalInsets will be called and after that we can
// resize the layout. Make sure that the window stays small for one frame until the
@@ -5318,11 +5285,6 @@
public void startExpand(float x, float y, boolean startTracking, float expandedHeight) {
startExpandMotion(x, y, startTracking, expandedHeight);
}
-
- @Override
- public void clearNotificationEffects() {
- mCentralSurfaces.clearNotificationEffects();
- }
}
private final class ShadeAccessibilityDelegate extends AccessibilityDelegate {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 0f85c76..880ba92 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -37,6 +37,7 @@
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.back.domain.interactor.BackActionInteractor;
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder;
@@ -560,7 +561,9 @@
void setExpandAnimationRunning(boolean running) {
if (mExpandAnimationRunning != running) {
// TODO(b/288507023): Remove this log.
- Log.d(TAG, "Setting mExpandAnimationRunning=" + running);
+ if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "Setting mExpandAnimationRunning=" + running);
+ }
if (running) {
mLaunchAnimationTimeout = mClock.uptimeMillis() + 5000;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index 02f337a..447a15d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -33,6 +33,8 @@
* {@link com.android.systemui.keyguard.KeyguardViewMediator} and others.
*/
public interface ShadeController extends CoreStartable {
+ /** True if the shade UI is enabled on this particular Android variant and false otherwise. */
+ boolean isShadeEnabled();
/** Make our window larger and the shade expanded */
void instantExpandShade();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
index 5f95bca..82959ee 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
@@ -23,6 +23,7 @@
/** Empty implementation of ShadeController for variants of Android without shades. */
@SysUISingleton
open class ShadeControllerEmptyImpl @Inject constructor() : ShadeController {
+ override fun isShadeEnabled() = false
override fun start() {}
override fun instantExpandShade() {}
override fun instantCollapseShade() {}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index 9a3e4e5..367449b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -114,6 +114,11 @@
}
@Override
+ public boolean isShadeEnabled() {
+ return true;
+ }
+
+ @Override
public void instantExpandShade() {
// Make our window larger and the panel expanded.
makeExpandedVisible(true /* force */);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 1121834..cdbea81 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -248,9 +248,6 @@
/** Sends an external (e.g. Status Bar) touch event to the Shade touch handler. */
fun handleExternalTouch(event: MotionEvent): Boolean
- /** Starts tracking a shade expansion gesture that originated from the status bar. */
- fun startTrackingExpansionFromStatusBar()
-
/**
* Performs haptic feedback from a view with a haptic feedback constant.
*
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
index 6a2bef2..1893756 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
@@ -86,7 +86,6 @@
override fun handleExternalTouch(event: MotionEvent): Boolean {
return false
}
- override fun startTrackingExpansionFromStatusBar() {}
override fun performHapticFeedback(constant: Int) {}
override val shadeHeadsUpTracker = ShadeHeadsUpTrackerEmptyImpl()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
index f1e75b1..3f7512a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
@@ -76,7 +76,7 @@
scenesProvider: Provider<Set<@JvmSuppressWildcards Scene>>,
layoutInsetController: NotificationInsetsController,
): WindowRootView {
- return if (Flags.SCENE_CONTAINER_ENABLED && sceneContainerFlags.isEnabled()) {
+ return if (sceneContainerFlags.isEnabled()) {
val sceneWindowRootView =
layoutInflater.inflate(R.layout.scene_window_root, null) as SceneWindowRootView
sceneWindowRootView.init(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 0aedbf3..c62546f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -140,8 +140,9 @@
}
override fun onIntentStarted(willAnimate: Boolean) {
- // TODO(b/288507023): Remove this log.
- Log.d(TAG, "onIntentStarted(willAnimate=$willAnimate)")
+ if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "onIntentStarted(willAnimate=$willAnimate)")
+ }
notificationExpansionRepository.setIsExpandAnimationRunning(willAnimate)
notificationEntry.isExpandAnimationRunning = willAnimate
@@ -172,8 +173,9 @@
}
override fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean?) {
- // TODO(b/288507023): Remove this log.
- Log.d(TAG, "onLaunchAnimationCancelled()")
+ if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "onLaunchAnimationCancelled()")
+ }
// TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started
// here?
@@ -191,8 +193,9 @@
}
override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
- // TODO(b/288507023): Remove this log.
- Log.d(TAG, "onLaunchAnimationEnd()")
+ if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "onLaunchAnimationEnd()")
+ }
jankMonitor.end(InteractionJankMonitor.CUJ_NOTIFICATION_APP_START)
notification.isExpandAnimationRunning = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt
index 8754c4a..6f0a97a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/NotificationExpansionRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.data.repository
import android.util.Log
+import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -40,8 +41,9 @@
/** Sets whether the notification expansion animation is currently running. */
fun setIsExpandAnimationRunning(running: Boolean) {
- // TODO(b/288507023): Remove this log.
- Log.d(TAG, "setIsExpandAnimationRunning(running=$running)")
+ if (ActivityLaunchAnimator.DEBUG_LAUNCH_ANIMATION) {
+ Log.d(TAG, "setIsExpandAnimationRunning(running=$running)")
+ }
_isExpandAnimationRunning.value = running
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 67c0c94..cfa481e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -265,10 +265,6 @@
boolean isOverviewEnabled();
- void showPinningEnterExitToast(boolean entering);
-
- void showPinningEscapeToast();
-
void setBouncerShowing(boolean bouncerShowing);
boolean isScreenFullyOff();
@@ -295,16 +291,12 @@
@VisibleForTesting
void updateScrimController();
- boolean isKeyguardShowing();
-
boolean shouldIgnoreTouch();
boolean isDeviceInteractive();
void awakenDreams();
- void clearNotificationEffects();
-
boolean isBouncerShowing();
boolean isBouncerShowingScrimmed();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 0a57046..28bb581 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -510,16 +510,6 @@
}
@Override
- public void showPinningEnterExitToast(boolean entering) {
- mCentralSurfaces.showPinningEnterExitToast(entering);
- }
-
- @Override
- public void showPinningEscapeToast() {
- mCentralSurfaces.showPinningEscapeToast();
- }
-
- @Override
public void showScreenPinningRequest(int taskId) {
if (mKeyguardStateController.isShowing()) {
// Don't allow apps to trigger this from keyguard.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt
index 98ba6d9..ff380db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt
@@ -69,8 +69,6 @@
) {}
override fun getNavigationBarView(): NavigationBarView? = null
override fun isOverviewEnabled() = false
- override fun showPinningEnterExitToast(entering: Boolean) {}
- override fun showPinningEscapeToast() {}
override fun setBouncerShowing(bouncerShowing: Boolean) {}
override fun isScreenFullyOff() = false
override fun showScreenPinningRequest(taskId: Int, allowCancel: Boolean) {}
@@ -81,11 +79,9 @@
override fun setTransitionToFullShadeProgress(transitionToFullShadeProgress: Float) {}
override fun setPrimaryBouncerHiddenFraction(expansion: Float) {}
override fun updateScrimController() {}
- override fun isKeyguardShowing() = false
override fun shouldIgnoreTouch() = false
override fun isDeviceInteractive() = false
override fun awakenDreams() {}
- override fun clearNotificationEffects() {}
override fun isBouncerShowing() = false
override fun isBouncerShowingScrimmed() = false
override fun isBouncerShowingOverDream() = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index b45a688..490c469 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -24,11 +24,9 @@
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS;
-
import static androidx.core.view.ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
import static androidx.core.view.ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
import static androidx.lifecycle.Lifecycle.State.RESUMED;
-
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
import static com.android.systemui.charging.WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
@@ -1433,7 +1431,7 @@
// - QS is expanded and we're swiping - swiping up now will hide QS, not dismiss the
// keyguard.
// - Shade is in QQS over keyguard - swiping up should take us back to keyguard
- if (!isKeyguardShowing()
+ if (!mKeyguardStateController.isShowing()
|| mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()
|| mKeyguardStateController.isOccluded()
|| !mKeyguardStateController.canDismissLockScreen()
@@ -2548,16 +2546,6 @@
return mNavigationBarController.isOverviewEnabled(mDisplayId);
}
- @Override
- public void showPinningEnterExitToast(boolean entering) {
- mNavigationBarController.showPinningEnterExitToast(mDisplayId, entering);
- }
-
- @Override
- public void showPinningEscapeToast() {
- mNavigationBarController.showPinningEscapeToast(mDisplayId);
- }
-
/**
* Propagation of the bouncer state, indicating that it's fully visible.
*/
@@ -2883,7 +2871,8 @@
if (mDevicePolicyManager.getCameraDisabled(null,
mLockscreenUserManager.getCurrentUserId())) {
return false;
- } else if (isKeyguardShowing() && mStatusBarKeyguardViewManager.isSecure()) {
+ } else if (mKeyguardStateController.isShowing()
+ && mStatusBarKeyguardViewManager.isSecure()) {
// Check if the admin has disabled the camera specifically for the keyguard
return (mDevicePolicyManager.getKeyguardDisabledFeatures(null,
mLockscreenUserManager.getCurrentUserId())
@@ -2999,12 +2988,6 @@
Trace.endSection();
}
-
- @Override
- public boolean isKeyguardShowing() {
- return mKeyguardStateController.isShowing();
- }
-
@Override
public boolean shouldIgnoreTouch() {
return (mStatusBarStateController.isDozing()
@@ -3153,11 +3136,7 @@
}
}
- /**
- * Clear Buzz/Beep/Blink.
- */
- @Override
- public void clearNotificationEffects() {
+ private void clearNotificationEffects() {
try {
mBarService.clearNotificationEffects();
} catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 16c2e36..dcbaac2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -17,9 +17,11 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.os.RemoteException;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -31,6 +33,7 @@
public class HeadsUpTouchHelper implements Gefingerpoken {
private final HeadsUpManagerPhone mHeadsUpManager;
+ private final IStatusBarService mStatusBarService;
private final Callback mCallback;
private int mTrackingPointer;
private final float mTouchSlop;
@@ -43,9 +46,11 @@
private ExpandableNotificationRow mPickedChild;
public HeadsUpTouchHelper(HeadsUpManagerPhone headsUpManager,
+ IStatusBarService statusBarService,
Callback callback,
HeadsUpNotificationViewController notificationPanelView) {
mHeadsUpManager = headsUpManager;
+ mStatusBarService = statusBarService;
mCallback = callback;
mPanel = notificationPanelView;
Context context = mCallback.getContext();
@@ -119,7 +124,7 @@
// This call needs to be after the expansion start otherwise we will get a
// flicker of one frame as it's not expanded yet.
mHeadsUpManager.unpinAll(true);
- mPanel.clearNotificationEffects();
+ clearNotificationEffects();
endMotion();
return true;
}
@@ -175,6 +180,14 @@
mTouchingHeadsUpView = false;
}
+ private void clearNotificationEffects() {
+ try {
+ mStatusBarService.clearNotificationEffects();
+ } catch (RemoteException e) {
+ // Won't fail unless the world has ended.
+ }
+ }
+
public interface Callback {
ExpandableView getChildAtRawPosition(float touchX, float touchY);
boolean isExpanded();
@@ -191,8 +204,5 @@
/** Called when a MotionEvent is about to trigger expansion. */
void startExpand(float newX, float newY, boolean startTracking, float expandedHeight);
-
- /** Clear any effects that were added for the expansion. */
- void clearNotificationEffects();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 23b0ee0..dd471aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -206,7 +206,6 @@
shadeLogger.logMotionEvent(event, "top edge touch ignored")
return true
}
- shadeViewController.startTrackingExpansionFromStatusBar()
}
return shadeViewController.handleExternalTouch(event)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 27b8406..3afbbfd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import static android.view.WindowInsets.Type.navigationBars;
-
import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
@@ -67,9 +66,12 @@
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor;
+import com.android.systemui.keyguard.shared.model.DismissAction;
+import com.android.systemui.keyguard.shared.model.KeyguardDone;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.TaskbarDelegate;
@@ -104,6 +106,7 @@
import javax.inject.Inject;
import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.ExperimentalCoroutinesApi;
/**
* Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
@@ -111,7 +114,7 @@
* which is in turn, reported to this class by the current
* {@link com.android.keyguard.KeyguardViewController}.
*/
-@SysUISingleton
+@ExperimentalCoroutinesApi @SysUISingleton
public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
ShadeExpansionListener, NavigationModeController.ModeChangedListener,
@@ -338,6 +341,7 @@
}
};
private Lazy<WindowManagerLockscreenVisibilityInteractor> mWmLockscreenVisibilityInteractor;
+ private Lazy<KeyguardDismissActionInteractor> mKeyguardDismissActionInteractor;
@Inject
public StatusBarKeyguardViewManager(
@@ -367,7 +371,8 @@
ActivityStarter activityStarter,
KeyguardTransitionInteractor keyguardTransitionInteractor,
@Main CoroutineDispatcher mainDispatcher,
- Lazy<WindowManagerLockscreenVisibilityInteractor> wmLockscreenVisibilityInteractor
+ Lazy<WindowManagerLockscreenVisibilityInteractor> wmLockscreenVisibilityInteractor,
+ Lazy<KeyguardDismissActionInteractor> keyguardDismissActionInteractorLazy
) {
mContext = context;
mViewMediatorCallback = callback;
@@ -400,6 +405,7 @@
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mMainDispatcher = mainDispatcher;
mWmLockscreenVisibilityInteractor = wmLockscreenVisibilityInteractor;
+ mKeyguardDismissActionInteractor = keyguardDismissActionInteractorLazy;
}
KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@@ -692,6 +698,45 @@
public void dismissWithAction(OnDismissAction r, Runnable cancelAction,
boolean afterKeyguardGone, String message) {
+ if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ if (r == null) {
+ return;
+ }
+ Trace.beginSection("StatusBarKeyguardViewManager#interactorDismissWithAction");
+ if (afterKeyguardGone) {
+ mKeyguardDismissActionInteractor.get().setDismissAction(
+ new DismissAction.RunAfterKeyguardGone(
+ () -> {
+ r.onDismiss();
+ return null;
+ },
+ (cancelAction != null) ? cancelAction : () -> {},
+ message == null ? "" : message,
+ r.willRunAnimationOnKeyguard()
+ )
+ );
+ } else {
+ mKeyguardDismissActionInteractor.get().setDismissAction(
+ new DismissAction.RunImmediately(
+ () -> {
+ if (r.onDismiss()) {
+ return KeyguardDone.LATER;
+ } else {
+ return KeyguardDone.IMMEDIATE;
+ }
+ },
+ (cancelAction != null) ? cancelAction : () -> {},
+ message == null ? "" : message,
+ r.willRunAnimationOnKeyguard()
+ )
+ );
+ }
+
+ showBouncer(true);
+ Trace.endSection();
+ return;
+ }
+
if (mKeyguardStateController.isShowing()) {
try {
Trace.beginSection("StatusBarKeyguardViewManager#dismissWithAction");
@@ -705,9 +750,12 @@
return;
}
- mAfterKeyguardGoneAction = r;
- mKeyguardGoneCancelAction = cancelAction;
- mDismissActionWillAnimateOnKeyguard = r != null && r.willRunAnimationOnKeyguard();
+ if (!mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ mAfterKeyguardGoneAction = r;
+ mKeyguardGoneCancelAction = cancelAction;
+ mDismissActionWillAnimateOnKeyguard = r != null
+ && r.willRunAnimationOnKeyguard();
+ }
// If there is an alternate auth interceptor (like the UDFPS), show that one
// instead of the bouncer.
@@ -755,6 +803,12 @@
* Adds a {@param runnable} to be executed after Keyguard is gone.
*/
public void addAfterKeyguardGoneRunnable(Runnable runnable) {
+ if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ if (runnable != null) {
+ mKeyguardDismissActionInteractor.get().runAfterKeyguardGone(runnable);
+ }
+ return;
+ }
mAfterKeyguardGoneRunnables.add(runnable);
}
@@ -936,7 +990,11 @@
// We update the state (which will show the keyguard) only if an animation will run on
// the keyguard. If there is no animation, we wait before updating the state so that we
// go directly from bouncer to launcher/app.
- if (mDismissActionWillAnimateOnKeyguard) {
+ if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ if (mKeyguardDismissActionInteractor.get().runDismissAnimationOnKeyguard()) {
+ updateStates();
+ }
+ } else if (mDismissActionWillAnimateOnKeyguard) {
updateStates();
}
} else if (finishRunnable != null) {
@@ -1059,6 +1117,9 @@
}
private void executeAfterKeyguardGoneAction() {
+ if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) {
+ return;
+ }
if (mAfterKeyguardGoneAction != null) {
mAfterKeyguardGoneAction.onDismiss();
mAfterKeyguardGoneAction = null;
@@ -1351,10 +1412,10 @@
/**
* Notifies that the user has authenticated by other means than using the bouncer, for example,
- * fingerprint.
+ * fingerprint and the keyguard should immediately dismiss.
*/
public void notifyKeyguardAuthenticated(boolean strongAuth) {
- mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
+ mPrimaryBouncerInteractor.notifyKeyguardAuthenticatedBiometrics(strongAuth);
if (mAlternateBouncerInteractor.isVisibleState()) {
hideAlternateBouncer(false);
@@ -1442,6 +1503,8 @@
pw.println(" isBouncerShowing(): " + isBouncerShowing());
pw.println(" bouncerIsOrWillBeShowing(): " + primaryBouncerIsOrWillBeShowing());
pw.println(" Registered KeyguardViewManagerCallbacks:");
+ pw.println(" refactorKeyguardDismissIntent enabled:"
+ + mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT));
for (KeyguardViewManagerCallback callback : mCallbacks) {
pw.println(" " + callback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 9b0daca..945cc6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -38,8 +38,6 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.bluetooth.BluetoothRepository;
import com.android.systemui.statusbar.policy.bluetooth.ConnectionStatusModel;
@@ -64,7 +62,6 @@
CachedBluetoothDevice.Callback, LocalBluetoothProfileManager.ServiceListener {
private static final String TAG = "BluetoothController";
- private final FeatureFlags mFeatureFlags;
private final DumpManager mDumpManager;
private final BluetoothLogger mLogger;
private final BluetoothRepository mBluetoothRepository;
@@ -89,7 +86,6 @@
@Inject
public BluetoothControllerImpl(
Context context,
- FeatureFlags featureFlags,
UserTracker userTracker,
DumpManager dumpManager,
BluetoothLogger logger,
@@ -97,7 +93,6 @@
@Main Looper mainLooper,
@Nullable LocalBluetoothManager localBluetoothManager,
@Nullable BluetoothAdapter bluetoothAdapter) {
- mFeatureFlags = featureFlags;
mDumpManager = dumpManager;
mLogger = logger;
mBluetoothRepository = bluetoothRepository;
@@ -252,37 +247,8 @@
}
private void updateConnected() {
- if (mFeatureFlags.isEnabled(Flags.NEW_BLUETOOTH_REPOSITORY)) {
- mBluetoothRepository.fetchConnectionStatusInBackground(
- getDevices(), this::onConnectionStatusFetched);
- } else {
- updateConnectedOld();
- }
- }
-
- /** Used only if {@link Flags.NEW_BLUETOOTH_REPOSITORY} is *not* enabled. */
- private void updateConnectedOld() {
- // Make sure our connection state is up to date.
- int state = mLocalBluetoothManager.getBluetoothAdapter().getConnectionState();
- List<CachedBluetoothDevice> newList = new ArrayList<>();
- // If any of the devices are in a higher state than the adapter, move the adapter into
- // that state.
- for (CachedBluetoothDevice device : getDevices()) {
- int maxDeviceState = device.getMaxConnectionState();
- if (maxDeviceState > state) {
- state = maxDeviceState;
- }
- if (device.isConnected()) {
- newList.add(device);
- }
- }
-
- if (newList.isEmpty() && state == BluetoothAdapter.STATE_CONNECTED) {
- // If somehow we think we are connected, but have no connected devices, we aren't
- // connected.
- state = BluetoothAdapter.STATE_DISCONNECTED;
- }
- onConnectionStatusFetched(new ConnectionStatusModel(state, newList));
+ mBluetoothRepository.fetchConnectionStatusInBackground(
+ getDevices(), this::onConnectionStatusFetched);
}
private void onConnectionStatusFetched(ConnectionStatusModel status) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index 61acacd..33d4097 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -113,6 +113,7 @@
// For posture tests:
`when`(mockKeyguardPinView.buttons).thenReturn(arrayOf())
`when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6)
+ `when`(featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE)).thenReturn(false)
objectKeyguardPINView =
View.inflate(mContext, R.layout.keyguard_pin_view, null)
@@ -122,6 +123,7 @@
private fun constructPinViewController(
mKeyguardPinView: KeyguardPINView
): KeyguardPinViewController {
+ mKeyguardPinView.setIsLockScreenLandscapeEnabled(false)
return KeyguardPinViewController(
mKeyguardPinView,
keyguardUpdateMonitor,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 5da919b..7c1861e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -43,6 +43,7 @@
import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate
import com.android.systemui.biometrics.SideFpsController
import com.android.systemui.biometrics.SideFpsUiRequestSource
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
import com.android.systemui.classifier.FalsingA11yDelegate
import com.android.systemui.classifier.FalsingCollector
@@ -72,6 +73,7 @@
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.GlobalSettings
import com.google.common.truth.Truth
+import dagger.Lazy
import java.util.Optional
import junit.framework.Assert
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -154,6 +156,7 @@
private lateinit var sceneInteractor: SceneInteractor
private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
private lateinit var authenticationInteractor: AuthenticationInteractor
+ @Mock private lateinit var primaryBouncerInteractor: Lazy<PrimaryBouncerInteractor>
private lateinit var sceneTransitionStateFlow: MutableStateFlow<ObservableTransitionState>
private lateinit var underTest: KeyguardSecurityContainerController
@@ -193,6 +196,7 @@
featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
featureFlags.set(Flags.BOUNCER_USER_SWITCHER, false)
featureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false)
+ featureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)
keyguardPasswordViewController =
KeyguardPasswordViewController(
@@ -257,7 +261,8 @@
userInteractor,
deviceProvisionedController,
faceAuthAccessibilityDelegate,
- keyguardTransitionInteractor
+ keyguardTransitionInteractor,
+ primaryBouncerInteractor,
) {
authenticationInteractor
}
@@ -381,6 +386,36 @@
}
@Test
+ fun showSecurityScreen_oneHandedMode_flagEnabled_oneHandedMode_simpin() {
+ testableResources.addOverride(R.bool.can_use_one_handed_bouncer, true)
+ setupGetSecurityView(SecurityMode.SimPin)
+ verify(view)
+ .initMode(
+ eq(KeyguardSecurityContainer.MODE_ONE_HANDED),
+ eq(globalSettings),
+ eq(falsingManager),
+ eq(userSwitcherController),
+ any(),
+ eq(falsingA11yDelegate)
+ )
+ }
+
+ @Test
+ fun showSecurityScreen_oneHandedMode_flagEnabled_oneHandedMode_simpuk() {
+ testableResources.addOverride(R.bool.can_use_one_handed_bouncer, true)
+ setupGetSecurityView(SecurityMode.SimPuk)
+ verify(view)
+ .initMode(
+ eq(KeyguardSecurityContainer.MODE_ONE_HANDED),
+ eq(globalSettings),
+ eq(falsingManager),
+ eq(userSwitcherController),
+ any(),
+ eq(falsingA11yDelegate)
+ )
+ }
+
+ @Test
fun showSecurityScreen_twoHandedMode_flagEnabled_noOneHandedMode() {
testableResources.addOverride(R.bool.can_use_one_handed_bouncer, true)
setupGetSecurityView(SecurityMode.Password)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
index 979fc83..a2dc776 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
@@ -17,11 +17,9 @@
package com.android.keyguard;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
-
import static com.android.keyguard.LockIconView.ICON_LOCK;
import static com.android.keyguard.LockIconView.ICON_UNLOCK;
import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
@@ -40,8 +38,8 @@
import androidx.test.filters.SmallTest;
-import com.android.settingslib.udfps.UdfpsOverlayParams;
import com.android.systemui.biometrics.UdfpsController;
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
import com.android.systemui.doze.util.BurnInHelperKt;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
index 576f689..b478d5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
@@ -17,7 +17,6 @@
package com.android.systemui.accessibility;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
@@ -41,9 +40,7 @@
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
-
-import dagger.Lazy;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
import org.junit.Test;
@@ -64,12 +61,12 @@
@Mock
private NotificationShadeWindowController mNotificationShadeController;
@Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
private ShadeController mShadeController;
@Mock
private ShadeViewController mShadeViewController;
@Mock
- private Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
- @Mock
private Optional<Recents> mRecentsOptional;
@Mock
private TelecomManager mTelecomManager;
@@ -84,9 +81,15 @@
MockitoAnnotations.initMocks(this);
mContext.addMockSystemService(TelecomManager.class, mTelecomManager);
mContext.addMockSystemService(InputManager.class, mInputManager);
- mSystemActions = new SystemActions(mContext, mUserTracker, mNotificationShadeController,
- mShadeController, () -> mShadeViewController, mCentralSurfacesOptionalLazy,
- mRecentsOptional, mDisplayTracker);
+ mSystemActions = new SystemActions(
+ mContext,
+ mUserTracker,
+ mNotificationShadeController,
+ mKeyguardStateController,
+ mShadeController,
+ () -> mShadeViewController,
+ mRecentsOptional,
+ mDisplayTracker);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
deleted file mode 100644
index a93af7d..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
+++ /dev/null
@@ -1,164 +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.biometrics
-
-import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
-import android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT
-import android.hardware.biometrics.BiometricConstants
-import android.hardware.face.FaceManager
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
-import android.view.View
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.RoboPilotTest
-import com.android.systemui.SysuiTestCase
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.times
-import org.mockito.junit.MockitoJUnit
-
-
-@RunWith(AndroidJUnit4::class)
-@RunWithLooper(setAsMainLooper = true)
-@SmallTest
-@RoboPilotTest
-class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() {
-
- @JvmField
- @Rule
- var mockitoRule = MockitoJUnit.rule()
-
- @Mock
- private lateinit var callback: AuthBiometricView.Callback
-
- @Mock
- private lateinit var panelController: AuthPanelController
-
- private lateinit var biometricView: AuthBiometricFingerprintAndFaceView
-
- @Before
- fun setup() {
- biometricView = R.layout.auth_biometric_fingerprint_and_face_view
- .asTestAuthBiometricView(mContext, callback, panelController)
- waitForIdleSync()
- }
-
- @After
- fun tearDown() {
- biometricView.destroyDialog()
- }
-
- @Test
- fun fingerprintSuccessDoesNotRequireExplicitConfirmation() {
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.onAuthenticationSucceeded(TYPE_FINGERPRINT)
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticated).isTrue()
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
- }
-
- @Test
- fun faceSuccessRequiresExplicitConfirmation() {
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.onAuthenticationSucceeded(TYPE_FACE)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticated).isFalse()
- assertThat(biometricView.isAuthenticating).isFalse()
- assertThat(biometricView.mConfirmButton.visibility).isEqualTo(View.GONE)
- verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
-
- // icon acts as confirm button
- biometricView.mIconView.performClick()
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticated).isTrue()
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED_AND_CONFIRMED)
- }
-
- @Test
- fun ignoresFaceErrors_faceIsNotClass3_notLockoutError() {
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.onError(TYPE_FACE, "not a face")
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticating).isTrue()
- verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_ERROR)
-
- biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
- }
-
- @Test
- fun doNotIgnoresFaceErrors_faceIsClass3_notLockoutError() {
- biometricView.isFaceClass3 = true
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.onError(TYPE_FACE, "not a face")
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticating).isTrue()
- verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_ERROR)
-
- biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
- }
-
- @Test
- fun doNotIgnoresFaceErrors_faceIsClass3_lockoutError() {
- biometricView.isFaceClass3 = true
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.onError(
- TYPE_FACE,
- FaceManager.getErrorString(
- biometricView.context,
- BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
- 0 /*vendorCode */
- )
- )
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticating).isTrue()
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
-
- biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback, times(2)).onAction(AuthBiometricView.Callback.ACTION_ERROR)
- }
-
-
- override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages()
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt
index cac618b..52bf350 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt
@@ -27,6 +27,7 @@
import com.airbnb.lottie.LottieAnimationView
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
@@ -63,7 +64,7 @@
setupFingerprintSensorProperties(FingerprintSensorProperties.TYPE_POWER_BUTTON)
controller = AuthBiometricFingerprintIconController(context, iconView, iconViewOverlay)
- assertThat(controller.getIconContentDescription(AuthBiometricView.STATE_AUTHENTICATING))
+ assertThat(controller.getIconContentDescription(BiometricState.STATE_AUTHENTICATING))
.isEqualTo(
context.resources.getString(
R.string.security_settings_sfps_enroll_find_sensor_message
@@ -76,7 +77,7 @@
setupFingerprintSensorProperties(FingerprintSensorProperties.TYPE_UDFPS_OPTICAL)
controller = AuthBiometricFingerprintIconController(context, iconView, iconViewOverlay)
- assertThat(controller.getIconContentDescription(AuthBiometricView.STATE_AUTHENTICATING))
+ assertThat(controller.getIconContentDescription(BiometricState.STATE_AUTHENTICATING))
.isEqualTo(context.resources.getString(R.string.fingerprint_dialog_touch_sensor))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
deleted file mode 100644
index 8e5d96b..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
+++ /dev/null
@@ -1,283 +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.biometrics
-
-import android.hardware.biometrics.BiometricAuthenticator
-import android.os.Bundle
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
-import android.view.View
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.RoboPilotTest
-import com.android.systemui.SysuiTestCase
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
-
-@RunWith(AndroidJUnit4::class)
-@RunWithLooper(setAsMainLooper = true)
-@SmallTest
-@RoboPilotTest
-class AuthBiometricFingerprintViewTest : SysuiTestCase() {
-
- @JvmField
- @Rule
- val mockitoRule = MockitoJUnit.rule()
-
- @Mock
- private lateinit var callback: AuthBiometricView.Callback
-
- @Mock
- private lateinit var panelController: AuthPanelController
-
- private lateinit var biometricView: AuthBiometricView
-
- private fun createView(allowDeviceCredential: Boolean = false): AuthBiometricFingerprintView {
- val view: AuthBiometricFingerprintView =
- R.layout.auth_biometric_fingerprint_view.asTestAuthBiometricView(
- mContext, callback, panelController, allowDeviceCredential = allowDeviceCredential
- )
- waitForIdleSync()
- return view
- }
-
- @Before
- fun setup() {
- biometricView = createView()
- }
-
- @After
- fun tearDown() {
- biometricView.destroyDialog()
- }
-
- @Test
- fun testOnAuthenticationSucceeded_noConfirmationRequired_sendsActionAuthenticated() {
- biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticated).isTrue()
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
- }
-
- @Test
- fun testOnAuthenticationSucceeded_confirmationRequired_updatesDialogContents() {
- biometricView.setRequireConfirmation(true)
- biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- // TODO: this should be tested in the subclasses
- if (biometricView.supportsRequireConfirmation()) {
- verify(callback, never()).onAction(ArgumentMatchers.anyInt())
- assertThat(biometricView.mNegativeButton.visibility).isEqualTo(View.GONE)
- assertThat(biometricView.mCancelButton.visibility).isEqualTo(View.VISIBLE)
- assertThat(biometricView.mCancelButton.isEnabled).isTrue()
- assertThat(biometricView.mConfirmButton.isEnabled).isTrue()
- assertThat(biometricView.mIndicatorView.text)
- .isEqualTo(mContext.getText(R.string.biometric_dialog_tap_confirm))
- assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
- } else {
- assertThat(biometricView.isAuthenticated).isTrue()
- verify(callback).onAction(eq(AuthBiometricView.Callback.ACTION_AUTHENTICATED))
- }
- }
-
- @Test
- fun testPositiveButton_sendsActionAuthenticated() {
- biometricView.mConfirmButton.performClick()
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
- assertThat(biometricView.isAuthenticated).isTrue()
- }
-
- @Test
- fun testNegativeButton_beforeAuthentication_sendsActionButtonNegative() {
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.mNegativeButton.performClick()
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_BUTTON_NEGATIVE)
- }
-
- @Test
- fun testCancelButton_whenPendingConfirmation_sendsActionUserCanceled() {
- biometricView.setRequireConfirmation(true)
- biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
-
- assertThat(biometricView.mNegativeButton.visibility).isEqualTo(View.GONE)
- biometricView.mCancelButton.performClick()
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_USER_CANCELED)
- }
-
- @Test
- fun testTryAgainButton_sendsActionTryAgain() {
- biometricView.mTryAgainButton.performClick()
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN)
- assertThat(biometricView.mTryAgainButton.visibility).isEqualTo(View.GONE)
- assertThat(biometricView.isAuthenticating).isTrue()
- }
-
- @Test
- fun testOnErrorSendsActionError() {
- biometricView.onError(BiometricAuthenticator.TYPE_FACE, "testError")
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR))
- }
-
- @Test
- fun testOnErrorShowsMessage() {
- // prevent error state from instantly returning to authenticating in the test
- biometricView.mAnimationDurationHideDialog = 10_000
-
- val message = "another error"
- biometricView.onError(BiometricAuthenticator.TYPE_FACE, message)
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticating).isFalse()
- assertThat(biometricView.isAuthenticated).isFalse()
- assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
- assertThat(biometricView.mIndicatorView.text).isEqualTo(message)
- }
-
- @Test
- fun testBackgroundClicked_sendsActionUserCanceled() {
- val view = View(mContext)
- biometricView.setBackgroundView(view)
- view.performClick()
-
- verify(callback).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED))
- }
-
- @Test
- fun testBackgroundClicked_afterAuthenticated_neverSendsUserCanceled() {
- val view = View(mContext)
- biometricView.setBackgroundView(view)
- biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
- waitForIdleSync()
- view.performClick()
-
- verify(callback, never())
- .onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED))
- }
-
- @Test
- fun testBackgroundClicked_whenSmallDialog_neverSendsUserCanceled() {
- biometricView.mLayoutParams = AuthDialog.LayoutParams(0, 0)
- biometricView.updateSize(AuthDialog.SIZE_SMALL)
- val view = View(mContext)
- biometricView.setBackgroundView(view)
- view.performClick()
-
- verify(callback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED))
- }
-
- @Test
- fun testIgnoresUselessHelp() {
- biometricView.mAnimationDurationHideDialog = 10_000
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticating).isTrue()
-
- val helpText = biometricView.mIndicatorView.text
- biometricView.onHelp(BiometricAuthenticator.TYPE_FINGERPRINT, "")
- waitForIdleSync()
-
- // text should not change
- assertThat(biometricView.mIndicatorView.text).isEqualTo(helpText)
- verify(callback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR))
- }
-
- @Test
- fun testRestoresState() {
- val requireConfirmation = true
- biometricView.mAnimationDurationHideDialog = 10_000
- val failureMessage = "testFailureMessage"
- biometricView.setRequireConfirmation(requireConfirmation)
- biometricView.onAuthenticationFailed(BiometricAuthenticator.TYPE_FACE, failureMessage)
- waitForIdleSync()
-
- val state = Bundle()
- biometricView.onSaveState(state)
- assertThat(biometricView.mTryAgainButton.visibility).isEqualTo(View.GONE)
- assertThat(state.getInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY))
- .isEqualTo(View.GONE)
- assertThat(state.getInt(AuthDialog.KEY_BIOMETRIC_STATE))
- .isEqualTo(AuthBiometricView.STATE_ERROR)
- assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
- assertThat(state.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING)).isTrue()
- assertThat(biometricView.mIndicatorView.text).isEqualTo(failureMessage)
- assertThat(state.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING))
- .isEqualTo(failureMessage)
-
- // TODO: Test dialog size. Should move requireConfirmation to buildBiometricPromptBundle
-
- // Create new dialog and restore the previous state into it
- biometricView.destroyDialog()
- biometricView = createView()
- biometricView.restoreState(state)
- biometricView.mAnimationDurationHideDialog = 10_000
- biometricView.setRequireConfirmation(requireConfirmation)
- waitForIdleSync()
-
- assertThat(biometricView.mTryAgainButton.visibility).isEqualTo(View.GONE)
- assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
-
- // TODO: Test restored text. Currently cannot test this, since it gets restored only after
- // dialog size is known.
- }
-
- @Test
- fun testCredentialButton_whenDeviceCredentialAllowed() {
- biometricView.destroyDialog()
- biometricView = createView(allowDeviceCredential = true)
-
- assertThat(biometricView.mUseCredentialButton.visibility).isEqualTo(View.VISIBLE)
- assertThat(biometricView.mNegativeButton.visibility).isEqualTo(View.GONE)
-
- biometricView.mUseCredentialButton.performClick()
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_USE_DEVICE_CREDENTIAL)
- }
-
- override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages()
-}
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 d10b81c..7775a05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -105,9 +105,6 @@
@Mock
lateinit var vibrator: VibratorHelper
- // TODO(b/278622168): remove with flag
- open val useNewBiometricPrompt = false
-
private val testScope = TestScope(StandardTestDispatcher())
private val fakeExecutor = FakeExecutor(FakeSystemClock())
private val biometricPromptRepository = FakePromptRepository()
@@ -137,7 +134,6 @@
@Before
fun setup() {
displayRepository = FakeDisplayRepository()
- featureFlags.set(Flags.BIOMETRIC_BP_STRONG, useNewBiometricPrompt)
featureFlags.set(Flags.ONE_WAY_HAPTICS_API_MIGRATION, false)
displayStateInteractor =
@@ -235,9 +231,7 @@
@Test
fun testActionCancel_panelInteractionDetectorDisable() {
val container = initializeFingerprintContainer()
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_USER_CANCELED
- )
+ container.mBiometricCallback.onUserCanceled()
waitForIdleSync()
verify(panelInteractionDetector).disable()
}
@@ -246,9 +240,7 @@
@Test
fun testActionAuthenticated_sendsDismissedAuthenticated() {
val container = initializeFingerprintContainer()
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_AUTHENTICATED
- )
+ container.mBiometricCallback.onAuthenticated()
waitForIdleSync()
verify(callback).onDismissed(
@@ -262,9 +254,7 @@
@Test
fun testActionUserCanceled_sendsDismissedUserCanceled() {
val container = initializeFingerprintContainer()
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_USER_CANCELED
- )
+ container.mBiometricCallback.onUserCanceled()
waitForIdleSync()
verify(callback).onSystemEvent(
@@ -282,9 +272,7 @@
@Test
fun testActionButtonNegative_sendsDismissedButtonNegative() {
val container = initializeFingerprintContainer()
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_BUTTON_NEGATIVE
- )
+ container.mBiometricCallback.onButtonNegative()
waitForIdleSync()
verify(callback).onDismissed(
@@ -300,9 +288,7 @@
val container = initializeFingerprintContainer(
authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK
)
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN
- )
+ container.mBiometricCallback.onButtonTryAgain()
waitForIdleSync()
verify(callback).onTryAgainPressed(authContainer?.requestId ?: 0L)
@@ -311,9 +297,7 @@
@Test
fun testActionError_sendsDismissedError() {
val container = initializeFingerprintContainer()
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_ERROR
- )
+ container.mBiometricCallback.onError()
waitForIdleSync()
verify(callback).onDismissed(
@@ -331,9 +315,7 @@
authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
BiometricManager.Authenticators.DEVICE_CREDENTIAL
)
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_USE_DEVICE_CREDENTIAL
- )
+ container.mBiometricCallback.onUseDeviceCredential()
waitForIdleSync()
verify(callback).onDeviceCredentialPressed(authContainer?.requestId ?: 0L)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest2.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest2.kt
deleted file mode 100644
index b56d055..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest2.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics
-
-import android.testing.TestableLooper
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import org.junit.runner.RunWith
-
-// TODO(b/278622168): remove with flag
-@RunWith(AndroidJUnit4::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-@SmallTest
-class AuthContainerViewTest2 : AuthContainerViewTest() {
- override val useNewBiometricPrompt = true
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 6d71dd5..d0b3833 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -17,22 +17,17 @@
package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
-import static android.hardware.biometrics.BiometricManager.Authenticators;
-
import static com.google.common.truth.Truth.assertThat;
-
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -48,7 +43,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -69,7 +63,6 @@
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
-import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserManager;
@@ -86,7 +79,6 @@
import com.android.internal.R;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.widget.LockPatternUtils;
-import com.android.settingslib.udfps.UdfpsUtils;
import com.android.systemui.RoboPilotTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
@@ -95,7 +87,6 @@
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.VibratorHelper;
@@ -207,10 +198,6 @@
@Before
public void setup() throws RemoteException {
- // TODO(b/278622168): remove with flag
- // AuthController simply passes this through to AuthContainerView (does not impact test)
- mFeatureFlags.set(Flags.BIOMETRIC_BP_STRONG, false);
-
mContextSpy = spy(mContext);
mExecution = new FakeExecution();
mTestableLooper = TestableLooper.get(this);
@@ -463,7 +450,7 @@
@Test
public void testShowInvoked_whenSystemRequested() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- verify(mDialog1).show(any(), any());
+ verify(mDialog1).show(any());
}
@Test
@@ -664,7 +651,7 @@
// 2) Client cancels authentication
showDialog(new int[0] /* sensorIds */, true /* credentialAllowed */);
- verify(mDialog1).show(any(), any());
+ verify(mDialog1).show(any());
final byte[] credentialAttestation = generateRandomHAT();
@@ -680,7 +667,7 @@
@Test
public void testShowNewDialog_beforeOldDialogDismissed_SkipsAnimations() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- verify(mDialog1).show(any(), any());
+ verify(mDialog1).show(any());
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
@@ -688,59 +675,7 @@
verify(mDialog1).dismissWithoutCallback(eq(false) /* animate */);
// Second dialog should be shown without animation
- verify(mDialog2).show(any(), any());
- }
-
- @Test
- public void testConfigurationPersists_whenOnConfigurationChanged() {
- showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- verify(mDialog1).show(any(), any());
-
- // Return that the UI is in "showing" state
- doAnswer(invocation -> {
- Object[] args = invocation.getArguments();
- Bundle savedState = (Bundle) args[0];
- savedState.putBoolean(AuthDialog.KEY_CONTAINER_GOING_AWAY, false);
- return null; // onSaveState returns void
- }).when(mDialog1).onSaveState(any());
-
- mAuthController.onConfigurationChanged(new Configuration());
-
- ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
- verify(mDialog1).onSaveState(captor.capture());
-
- // Old dialog doesn't animate
- verify(mDialog1).dismissWithoutCallback(eq(false /* animate */));
-
- // Saved state is restored into new dialog
- ArgumentCaptor<Bundle> captor2 = ArgumentCaptor.forClass(Bundle.class);
- verify(mDialog2).show(any(), captor2.capture());
-
- // TODO: This should check all values we want to save/restore
- assertEquals(captor.getValue(), captor2.getValue());
- }
-
- @Test
- public void testConfigurationPersists_whenBiometricFallbackToCredential() {
- showDialog(new int[] {1} /* sensorIds */, true /* credentialAllowed */);
- verify(mDialog1).show(any(), any());
-
- // Pretend that the UI is now showing device credential UI.
- doAnswer(invocation -> {
- Object[] args = invocation.getArguments();
- Bundle savedState = (Bundle) args[0];
- savedState.putBoolean(AuthDialog.KEY_CONTAINER_GOING_AWAY, false);
- savedState.putBoolean(AuthDialog.KEY_CREDENTIAL_SHOWING, true);
- return null; // onSaveState returns void
- }).when(mDialog1).onSaveState(any());
-
- mAuthController.onConfigurationChanged(new Configuration());
-
- // Check that the new dialog was initialized to the credential UI.
- ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
- verify(mDialog2).show(any(), captor.capture());
- assertEquals(Authenticators.DEVICE_CREDENTIAL,
- mAuthController.mLastBiometricPromptInfo.getAuthenticators());
+ verify(mDialog2).show(any());
}
@Test
@@ -1010,7 +945,7 @@
REQUEST_ID);
assertNull(mAuthController.mCurrentDialog);
- verify(mDialog1, never()).show(any(), any());
+ verify(mDialog1, never()).show(any());
}
private void showDialog(int[] sensorIds, boolean credentialAllowed) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
index 94244cd..9f24a9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
@@ -16,8 +16,6 @@
package com.android.systemui.biometrics
-import android.annotation.IdRes
-import android.content.Context
import android.hardware.biometrics.BiometricManager.Authenticators
import android.hardware.biometrics.ComponentInfoInternal
import android.hardware.biometrics.PromptInfo
@@ -27,57 +25,6 @@
import android.hardware.face.FaceSensorPropertiesInternal
import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
-import android.os.Bundle
-import android.testing.ViewUtils
-import android.view.LayoutInflater
-
-/**
- * Inflate the given BiometricPrompt layout and initialize it with test parameters.
- *
- * This attaches the view so be sure to call [destroyDialog] at the end of the test.
- */
-@IdRes
-internal fun <T : AuthBiometricView> Int.asTestAuthBiometricView(
- context: Context,
- callback: AuthBiometricView.Callback,
- panelController: AuthPanelController,
- allowDeviceCredential: Boolean = false,
- savedState: Bundle? = null,
- hideDelay: Int = 0
-): T {
- val view = LayoutInflater.from(context).inflate(this, null, false) as T
- view.mAnimationDurationLong = 0
- view.mAnimationDurationShort = 0
- view.mAnimationDurationHideDialog = hideDelay
- view.setPromptInfo(buildPromptInfo(allowDeviceCredential))
- view.setCallback(callback)
- view.restoreState(savedState)
- view.setPanelController(panelController)
-
- ViewUtils.attachView(view)
-
- return view
-}
-
-private fun buildPromptInfo(allowDeviceCredential: Boolean): PromptInfo {
- val promptInfo = PromptInfo()
- promptInfo.title = "Title"
- var authenticators = Authenticators.BIOMETRIC_WEAK
- if (allowDeviceCredential) {
- authenticators = authenticators or Authenticators.DEVICE_CREDENTIAL
- } else {
- promptInfo.negativeButtonText = "Negative"
- }
- promptInfo.authenticators = authenticators
- return promptInfo
-}
-
-/** Detach the view, if needed. */
-internal fun AuthBiometricView?.destroyDialog() {
- if (this != null && isAttachedToWindow) {
- ViewUtils.detachView(this)
- }
-}
/** Create [FingerprintSensorPropertiesInternal] for a test. */
internal fun fingerprintSensorPropertiesInternal(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index 6eb637b..c735419 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -37,12 +37,11 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.settingslib.udfps.UdfpsOverlayParams
-import com.android.settingslib.udfps.UdfpsUtils
import com.android.systemui.R
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.dump.DumpManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 755977f..b6bc7af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -74,12 +74,11 @@
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.settingslib.udfps.UdfpsOverlayParams;
-import com.android.settingslib.udfps.UdfpsUtils;
import com.android.systemui.R;
import com.android.systemui.RoboPilotTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
import com.android.systemui.biometrics.udfps.InteractionEvent;
import com.android.systemui.biometrics.udfps.NormalizedTouchData;
import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/udfps/UdfpsUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsUtilsTest.java
similarity index 84%
rename from packages/SettingsLib/tests/robotests/src/com/android/settingslib/udfps/UdfpsUtilsTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsUtilsTest.java
index f4f0ef9..2aeba9a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/udfps/UdfpsUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsUtilsTest.java
@@ -14,40 +14,45 @@
* limitations under the License.
*/
-package com.android.settingslib.udfps;
+package com.android.systemui.biometrics;
import static com.google.common.truth.Truth.assertThat;
-import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.view.Surface;
-import com.android.settingslib.R;
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
+import com.android.systemui.shared.biometrics.R;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class UdfpsUtilsTest {
+@RunWith(JUnit4.class)
+@SmallTest
+public class UdfpsUtilsTest extends SysuiTestCase {
@Rule
public final MockitoRule rule = MockitoJUnit.rule();
-
- private Context mContext;
private String[] mTouchHints;
private UdfpsUtils mUdfpsUtils;
@Before
public void setUp() {
- mContext = RuntimeEnvironment.application;
- mTouchHints = mContext.getResources().getStringArray(
- R.array.udfps_accessibility_touch_hints);
+ Resources resources = mContext.getResources();
+ mTouchHints = new String[]{
+ resources.getString(R.string.udfps_accessibility_touch_hints_left),
+ resources.getString(R.string.udfps_accessibility_touch_hints_down),
+ resources.getString(R.string.udfps_accessibility_touch_hints_right),
+ resources.getString(R.string.udfps_accessibility_touch_hints_up),
+ };
mUdfpsUtils = new UdfpsUtils();
}
@@ -86,7 +91,7 @@
@Test
- public void testTouchOutsideAreaNoRotation90Degrees() {
+ public void testTouchOutsideAreaRotation90Degrees() {
int rotation = Surface.ROTATION_90;
// touch at 0 degrees -> 90 degrees
assertThat(
@@ -120,7 +125,7 @@
@Test
- public void testTouchOutsideAreaNoRotation270Degrees() {
+ public void testTouchOutsideAreaRotation270Degrees() {
int rotation = Surface.ROTATION_270;
// touch at 0 degrees -> 270 degrees
assertThat(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
index d11c965..6d4588d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
@@ -19,16 +19,16 @@
import android.graphics.PointF
import android.graphics.RectF
import android.hardware.biometrics.SensorLocationInternal
-import androidx.test.ext.junit.runners.AndroidJUnit4
import android.testing.TestableLooper
import android.testing.ViewUtils
import android.view.LayoutInflater
import android.view.Surface
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.settingslib.udfps.UdfpsOverlayParams
import com.android.systemui.R
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
@@ -42,8 +42,8 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.nullable
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
private const val SENSOR_X = 50
private const val SENSOR_Y = 250
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
index 4d5e1b7..f15b738 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
@@ -25,9 +25,9 @@
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
-import com.android.systemui.biometrics.domain.model.BiometricModalities
import com.android.systemui.biometrics.faceSensorPropertiesInternal
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
+import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.PromptKind
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.util.mockito.any
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
index 9431d86..6b9c34b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
@@ -20,9 +20,9 @@
import android.test.suitebuilder.annotation.SmallTest
import android.view.MotionEvent
import android.view.Surface
-import com.android.settingslib.udfps.UdfpsOverlayParams
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
import com.android.systemui.coroutines.collectLastValue
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.StandardTestDispatcher
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
index be0276a..9e3c576 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
@@ -4,6 +4,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
import com.android.systemui.biometrics.promptInfo
+import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricUserInfo
import com.google.common.truth.Truth.assertThat
import org.junit.Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricModalitiesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricModalitiesTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
index 526b833..22e3e7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricModalitiesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.biometrics.domain.model
+package com.android.systemui.biometrics.shared.model
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
index ec2c1bc..99c2c40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
@@ -23,8 +23,8 @@
import android.view.Surface
import android.view.Surface.Rotation
import androidx.test.filters.SmallTest
-import com.android.settingslib.udfps.UdfpsOverlayParams
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index c03fd86..5834e31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -24,7 +24,6 @@
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.AuthBiometricView
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository
@@ -32,11 +31,12 @@
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
-import com.android.systemui.biometrics.domain.model.BiometricModalities
import com.android.systemui.biometrics.extractAuthenticatorTypes
import com.android.systemui.biometrics.faceSensorPropertiesInternal
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
+import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricModality
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.display.data.repository.FakeDisplayRepository
@@ -132,7 +132,7 @@
}
assertThat(message).isEqualTo(PromptMessage.Empty)
assertThat(size).isEqualTo(expectedSize)
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_IDLE)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_IDLE)
val startMessage = "here we go"
viewModel.showAuthenticating(startMessage, isRetry = false)
@@ -142,7 +142,7 @@
assertThat(authenticated?.isNotAuthenticated).isTrue()
assertThat(size).isEqualTo(expectedSize)
assertButtonsVisible(negative = expectedSize != PromptSize.SMALL)
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATING)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATING)
}
@Test
@@ -220,7 +220,7 @@
assertThat(authenticating).isTrue()
assertThat(authenticated?.isNotAuthenticated).isTrue()
assertThat(size).isEqualTo(if (authWithSmallPrompt) PromptSize.SMALL else PromptSize.MEDIUM)
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATING)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATING)
assertButtonsVisible(negative = !authWithSmallPrompt)
val delay = 1000L
@@ -240,9 +240,9 @@
assertThat(legacyState)
.isEqualTo(
if (expectConfirmation) {
- AuthBiometricView.STATE_PENDING_CONFIRMATION
+ BiometricState.STATE_PENDING_CONFIRMATION
} else {
- AuthBiometricView.STATE_AUTHENTICATED
+ BiometricState.STATE_AUTHENTICATED
}
)
assertButtonsVisible(
@@ -311,7 +311,7 @@
assertThat(size).isEqualTo(PromptSize.MEDIUM)
assertThat(message).isEqualTo(PromptMessage.Error(errorMessage))
assertThat(messageVisible).isTrue()
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_ERROR)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_ERROR)
// temporary error should disappear after a delay
errorJob.join()
@@ -326,11 +326,11 @@
assertThat(legacyState)
.isEqualTo(
if (restart) {
- AuthBiometricView.STATE_AUTHENTICATING
+ BiometricState.STATE_AUTHENTICATING
} else if (clearIconError) {
- AuthBiometricView.STATE_IDLE
+ BiometricState.STATE_IDLE
} else {
- AuthBiometricView.STATE_HELP
+ BiometricState.STATE_HELP
}
)
@@ -505,7 +505,7 @@
assertThat(authenticating).isFalse()
assertThat(authenticated?.isAuthenticated).isTrue()
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATED)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATED)
assertThat(canTryAgain).isFalse()
}
@@ -531,7 +531,7 @@
assertThat(authenticated?.isAuthenticated).isTrue()
if (testCase.isFaceOnly && expectConfirmation) {
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_PENDING_CONFIRMATION)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_PENDING_CONFIRMATION)
assertThat(size).isEqualTo(PromptSize.MEDIUM)
assertButtonsVisible(
@@ -543,7 +543,7 @@
assertThat(message).isEqualTo(PromptMessage.Empty)
assertButtonsVisible()
} else {
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATED)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATED)
}
}
@@ -580,7 +580,7 @@
assertThat(authenticating).isFalse()
assertThat(authenticated?.isAuthenticated).isTrue()
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATED)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATED)
assertThat(canTryAgain).isFalse()
}
@@ -614,7 +614,7 @@
viewModel.showHelp(helpMessage)
assertThat(size).isEqualTo(PromptSize.MEDIUM)
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_HELP)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_HELP)
assertThat(message).isEqualTo(PromptMessage.Help(helpMessage))
assertThat(messageVisible).isTrue()
@@ -642,9 +642,9 @@
assertThat(size).isEqualTo(PromptSize.MEDIUM)
if (confirmationRequired == true) {
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_PENDING_CONFIRMATION)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_PENDING_CONFIRMATION)
} else {
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATED)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATED)
}
assertThat(message).isEqualTo(PromptMessage.Help(helpMessage))
assertThat(messageVisible).isTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
index f892453..420fdba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -115,7 +115,7 @@
@Test
fun testShow_isScrimmed() {
underTest.show(true)
- verify(repository).setKeyguardAuthenticated(null)
+ verify(repository).setKeyguardAuthenticatedBiometrics(null)
verify(repository).setPrimaryStartingToHide(false)
verify(repository).setPrimaryScrimmed(true)
verify(repository).setPanelExpansion(EXPANSION_VISIBLE)
@@ -222,8 +222,8 @@
@Test
fun testNotifyKeyguardAuthenticated() {
- underTest.notifyKeyguardAuthenticated(true)
- verify(repository).setKeyguardAuthenticated(true)
+ underTest.notifyKeyguardAuthenticatedBiometrics(true)
+ verify(repository).setKeyguardAuthenticatedBiometrics(true)
}
@Test
@@ -241,7 +241,7 @@
@Test
fun testNotifyKeyguardAuthenticatedHandled() {
underTest.notifyKeyguardAuthenticatedHandled()
- verify(repository).setKeyguardAuthenticated(null)
+ verify(repository).setKeyguardAuthenticatedBiometrics(null)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index 4380af8..12090e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -185,6 +185,41 @@
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
+ @Test
+ fun onShown_againAfterSceneChange_resetsPassword() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
+ val password by collectLastValue(underTest.password)
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password
+ )
+ utils.authenticationRepository.setUnlocked(false)
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ underTest.onShown()
+
+ // The user types a password.
+ underTest.onPasswordInputChanged("password")
+ assertThat(password).isEqualTo("password")
+
+ // The user doesn't confirm the password, but navigates back to the lockscreen instead.
+ sceneInteractor.changeScene(SceneModel(SceneKey.Lockscreen), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen), "reason")
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
+
+ // The user navigates to the bouncer again.
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+
+ underTest.onShown()
+
+ // Ensure the previously-entered password is not shown.
+ assertThat(password).isEmpty()
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ }
+
companion object {
private const val ENTER_YOUR_PASSWORD = "Enter your password"
private const val WRONG_PASSWORD = "Wrong password"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
index ea2cad2..3c5212a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
@@ -203,6 +203,49 @@
}
@Test
+ fun onDragEnd_whenPatternTooShort() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
+ val message by collectLastValue(bouncerViewModel.message)
+ val selectedDots by collectLastValue(underTest.selectedDots)
+ val currentDot by collectLastValue(underTest.currentDot)
+ val throttlingDialogMessage by
+ collectLastValue(bouncerViewModel.throttlingDialogMessage)
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pattern
+ )
+ utils.authenticationRepository.setUnlocked(false)
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ underTest.onShown()
+
+ // Enter a pattern that's too short more than enough times that would normally trigger
+ // throttling if the pattern were not too short and wrong:
+ val attempts = FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING + 1
+ repeat(attempts) { attempt ->
+ underTest.onDragStart()
+ CORRECT_PATTERN.subList(
+ 0,
+ authenticationInteractor.minPatternLength - 1,
+ )
+ .forEach { coordinate ->
+ underTest.onDrag(
+ xPx = 30f * coordinate.x + 15,
+ yPx = 30f * coordinate.y + 15,
+ containerSizePx = 90,
+ verticalOffsetPx = 0f,
+ )
+ }
+
+ underTest.onDragEnd()
+
+ assertWithMessage("Attempt #$attempt").that(message?.text).isEqualTo(WRONG_PATTERN)
+ assertWithMessage("Attempt #$attempt").that(throttlingDialogMessage).isNull()
+ }
+ }
+
+ @Test
fun onDragEnd_correctAfterWrong() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 531f86a..a684221 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -314,6 +314,42 @@
}
@Test
+ fun onShown_againAfterSceneChange_resetsPin() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
+ val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setUnlocked(false)
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ underTest.onShown()
+
+ // The user types a PIN.
+ FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
+ underTest.onPinButtonClicked(digit)
+ }
+ assertThat(pin).isNotEmpty()
+
+ // The user doesn't confirm the PIN, but navigates back to the lockscreen instead.
+ sceneInteractor.changeScene(SceneModel(SceneKey.Lockscreen), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen), "reason")
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
+
+ // The user navigates to the bouncer again.
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+
+ underTest.onShown()
+
+ // Ensure the previously-entered PIN is not shown.
+ assertThat(pin).isEmpty()
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ }
+
+ @Test
fun backspaceButtonAppearance_withoutAutoConfirm_alwaysShown() =
testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
new file mode 100644
index 0000000..181cc88
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.RoboPilotTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.DismissAction
+import com.android.systemui.keyguard.shared.model.KeyguardDone
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
+class KeyguardDismissActionInteractorTest : SysuiTestCase() {
+ private lateinit var keyguardRepository: FakeKeyguardRepository
+ private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+
+ private lateinit var dispatcher: TestDispatcher
+ private lateinit var testScope: TestScope
+
+ private lateinit var dismissInteractorWithDependencies:
+ KeyguardDismissInteractorFactory.WithDependencies
+ private lateinit var underTest: KeyguardDismissActionInteractor
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ dispatcher = StandardTestDispatcher()
+ testScope = TestScope(dispatcher)
+
+ dismissInteractorWithDependencies =
+ KeyguardDismissInteractorFactory.create(
+ context = context,
+ testScope = testScope,
+ broadcastDispatcher = fakeBroadcastDispatcher,
+ dispatcher = dispatcher,
+ )
+ keyguardRepository = dismissInteractorWithDependencies.keyguardRepository
+ transitionRepository = FakeKeyguardTransitionRepository()
+
+ underTest =
+ KeyguardDismissActionInteractor(
+ keyguardRepository,
+ KeyguardTransitionInteractorFactory.create(
+ scope = testScope.backgroundScope,
+ repository = transitionRepository,
+ )
+ .keyguardTransitionInteractor,
+ dismissInteractorWithDependencies.interactor,
+ testScope.backgroundScope,
+ )
+ }
+
+ @Test
+ fun updateDismissAction_onRepoChange() =
+ testScope.runTest {
+ val dismissAction by collectLastValue(underTest.dismissAction)
+
+ val newDismissAction =
+ DismissAction.RunImmediately(
+ onDismissAction = { KeyguardDone.IMMEDIATE },
+ onCancelAction = {},
+ message = "",
+ willAnimateOnLockscreen = true,
+ )
+ keyguardRepository.setDismissAction(newDismissAction)
+ assertThat(dismissAction).isEqualTo(newDismissAction)
+ }
+
+ @Test
+ fun messageUpdate() =
+ testScope.runTest {
+ val message by collectLastValue(underTest.message)
+ keyguardRepository.setDismissAction(
+ DismissAction.RunImmediately(
+ onDismissAction = { KeyguardDone.IMMEDIATE },
+ onCancelAction = {},
+ message = "message",
+ willAnimateOnLockscreen = true,
+ )
+ )
+ assertThat(message).isEqualTo("message")
+ }
+
+ @Test
+ fun runDismissAnimationOnKeyguard_defaultStateFalse() =
+ testScope.runTest { assertThat(underTest.runDismissAnimationOnKeyguard()).isFalse() }
+
+ @Test
+ fun runDismissAnimationOnKeyguardUpdates() =
+ testScope.runTest {
+ val animate by collectLastValue(underTest.willAnimateDismissActionOnLockscreen)
+ keyguardRepository.setDismissAction(
+ DismissAction.RunImmediately(
+ onDismissAction = { KeyguardDone.IMMEDIATE },
+ onCancelAction = {},
+ message = "message",
+ willAnimateOnLockscreen = true,
+ )
+ )
+ assertThat(animate).isEqualTo(true)
+
+ keyguardRepository.setDismissAction(
+ DismissAction.RunImmediately(
+ onDismissAction = { KeyguardDone.IMMEDIATE },
+ onCancelAction = {},
+ message = "message",
+ willAnimateOnLockscreen = false,
+ )
+ )
+ assertThat(animate).isEqualTo(false)
+ }
+
+ @Test
+ fun executeDismissAction_dismissKeyguardRequestWithImmediateDismissAction_biometricAuthed() =
+ testScope.runTest {
+ val executeDismissAction by collectLastValue(underTest.executeDismissAction)
+
+ val onDismissAction = { KeyguardDone.IMMEDIATE }
+ keyguardRepository.setDismissAction(
+ DismissAction.RunImmediately(
+ onDismissAction = onDismissAction,
+ onCancelAction = {},
+ message = "message",
+ willAnimateOnLockscreen = true,
+ )
+ )
+ dismissInteractorWithDependencies.bouncerRepository.setKeyguardAuthenticatedBiometrics(
+ true
+ )
+ assertThat(executeDismissAction).isEqualTo(onDismissAction)
+ }
+
+ @Test
+ fun executeDismissAction_dismissKeyguardRequestWithoutImmediateDismissAction() =
+ testScope.runTest {
+ val executeDismissAction by collectLastValue(underTest.executeDismissAction)
+
+ // WHEN a keyguard action will run after the keyguard is gone
+ val onDismissAction = {}
+ keyguardRepository.setDismissAction(
+ DismissAction.RunAfterKeyguardGone(
+ dismissAction = onDismissAction,
+ onCancelAction = {},
+ message = "message",
+ willAnimateOnLockscreen = true,
+ )
+ )
+ assertThat(executeDismissAction).isNull()
+
+ // WHEN the keyguard is GONE
+ transitionRepository.sendTransitionStep(
+ TransitionStep(to = KeyguardState.GONE, transitionState = TransitionState.FINISHED)
+ )
+ assertThat(executeDismissAction).isNotNull()
+ }
+
+ @Test
+ fun resetDismissAction() =
+ testScope.runTest {
+ val resetDismissAction by collectLastValue(underTest.resetDismissAction)
+
+ keyguardRepository.setDismissAction(
+ DismissAction.RunAfterKeyguardGone(
+ dismissAction = {},
+ onCancelAction = {},
+ message = "message",
+ willAnimateOnLockscreen = true,
+ )
+ )
+ transitionRepository.sendTransitionStep(
+ TransitionStep(
+ to = KeyguardState.AOD,
+ transitionState = TransitionState.FINISHED,
+ )
+ )
+ assertThat(resetDismissAction).isEqualTo(Unit)
+ }
+
+ @Test
+ fun setDismissAction_callsCancelRunnableOnPreviousDismissAction() =
+ testScope.runTest {
+ val dismissAction by collectLastValue(underTest.dismissAction)
+ var previousDismissActionCancelCalled = false
+ keyguardRepository.setDismissAction(
+ DismissAction.RunImmediately(
+ onDismissAction = { KeyguardDone.IMMEDIATE },
+ onCancelAction = { previousDismissActionCancelCalled = true },
+ message = "",
+ willAnimateOnLockscreen = true,
+ )
+ )
+
+ val newDismissAction =
+ DismissAction.RunImmediately(
+ onDismissAction = { KeyguardDone.IMMEDIATE },
+ onCancelAction = {},
+ message = "",
+ willAnimateOnLockscreen = true,
+ )
+ underTest.setDismissAction(newDismissAction)
+
+ // THEN previous dismiss action got its onCancel called
+ assertThat(previousDismissActionCancelCalled).isTrue()
+
+ // THEN dismiss action is updated
+ assertThat(dismissAction).isEqualTo(newDismissAction)
+ }
+
+ @Test
+ fun handleDismissAction() =
+ testScope.runTest {
+ val dismissAction by collectLastValue(underTest.dismissAction)
+ underTest.handleDismissAction()
+ assertThat(dismissAction).isEqualTo(DismissAction.None)
+ }
+
+ @Test
+ fun setKeyguardDone() =
+ testScope.runTest {
+ val keyguardDoneTiming by
+ collectLastValue(dismissInteractorWithDependencies.interactor.keyguardDone)
+ runCurrent()
+
+ underTest.setKeyguardDone(KeyguardDone.LATER)
+ assertThat(keyguardDoneTiming).isEqualTo(KeyguardDone.LATER)
+
+ underTest.setKeyguardDone(KeyguardDone.IMMEDIATE)
+ assertThat(keyguardDoneTiming).isEqualTo(KeyguardDone.IMMEDIATE)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
new file mode 100644
index 0000000..c407b14
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.content.pm.UserInfo
+import android.service.trust.TrustAgentService
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.keyguard.TrustGrantFlags
+import com.android.systemui.RoboPilotTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.shared.model.DismissAction
+import com.android.systemui.keyguard.shared.model.KeyguardDone
+import com.android.systemui.keyguard.shared.model.TrustModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
+class KeyguardDismissInteractorTest : SysuiTestCase() {
+ private lateinit var dispatcher: TestDispatcher
+ private lateinit var testScope: TestScope
+
+ private lateinit var underTestDependencies: KeyguardDismissInteractorFactory.WithDependencies
+ private lateinit var underTest: KeyguardDismissInteractor
+ private val userInfo = UserInfo(0, "", 0)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ dispatcher = StandardTestDispatcher()
+ testScope = TestScope(dispatcher)
+
+ underTestDependencies =
+ KeyguardDismissInteractorFactory.create(
+ context = context,
+ testScope = testScope,
+ broadcastDispatcher = fakeBroadcastDispatcher,
+ dispatcher = dispatcher,
+ )
+ underTest = underTestDependencies.interactor
+ underTestDependencies.userRepository.setUserInfos(listOf(userInfo))
+ }
+
+ @Test
+ fun biometricAuthenticatedRequestDismissKeyguard_noDismissAction() =
+ testScope.runTest {
+ val dismissKeyguardRequestWithoutImmediateDismissAction by
+ collectLastValue(underTest.dismissKeyguardRequestWithoutImmediateDismissAction)
+
+ underTestDependencies.bouncerRepository.setKeyguardAuthenticatedBiometrics(null)
+ assertThat(dismissKeyguardRequestWithoutImmediateDismissAction).isNull()
+
+ underTestDependencies.bouncerRepository.setKeyguardAuthenticatedBiometrics(true)
+ assertThat(dismissKeyguardRequestWithoutImmediateDismissAction).isEqualTo(Unit)
+ }
+
+ @Test
+ fun onTrustGrantedRequestDismissKeyguard_noDismissAction() =
+ testScope.runTest {
+ val dismissKeyguardRequestWithoutImmediateDismissAction by
+ collectLastValue(underTest.dismissKeyguardRequestWithoutImmediateDismissAction)
+ underTestDependencies.trustRepository.setRequestDismissKeyguard(
+ TrustModel(
+ true,
+ 0,
+ TrustGrantFlags(0),
+ )
+ )
+ assertThat(dismissKeyguardRequestWithoutImmediateDismissAction).isNull()
+
+ underTestDependencies.powerRepository.setInteractive(true)
+ underTestDependencies.trustRepository.setRequestDismissKeyguard(
+ TrustModel(
+ true,
+ 0,
+ TrustGrantFlags(TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD),
+ )
+ )
+ assertThat(dismissKeyguardRequestWithoutImmediateDismissAction).isEqualTo(Unit)
+ }
+
+ @Test
+ fun primaryAuthenticated_noDismissAction() =
+ testScope.runTest {
+ val dismissKeyguardRequestWithoutImmediateDismissAction by
+ collectLastValue(underTest.dismissKeyguardRequestWithoutImmediateDismissAction)
+ underTestDependencies.userRepository.setSelectedUserInfo(userInfo)
+ runCurrent()
+
+ // authenticated different user
+ underTestDependencies.bouncerRepository.setKeyguardAuthenticatedPrimaryAuth(22)
+ assertThat(dismissKeyguardRequestWithoutImmediateDismissAction).isNull()
+
+ // authenticated correct user
+ underTestDependencies.bouncerRepository.setKeyguardAuthenticatedPrimaryAuth(userInfo.id)
+ assertThat(dismissKeyguardRequestWithoutImmediateDismissAction).isEqualTo(Unit)
+ }
+
+ @Test
+ fun userRequestedBouncerWhenAlreadyAuthenticated_noDismissAction() =
+ testScope.runTest {
+ val dismissKeyguardRequestWithoutImmediateDismissAction by
+ collectLastValue(underTest.dismissKeyguardRequestWithoutImmediateDismissAction)
+ underTestDependencies.userRepository.setSelectedUserInfo(userInfo)
+ runCurrent()
+
+ // requested from different user
+ underTestDependencies.bouncerRepository.setUserRequestedBouncerWhenAlreadyAuthenticated(
+ 22
+ )
+ assertThat(dismissKeyguardRequestWithoutImmediateDismissAction).isNull()
+
+ // requested from correct user
+ underTestDependencies.bouncerRepository.setUserRequestedBouncerWhenAlreadyAuthenticated(
+ userInfo.id
+ )
+ assertThat(dismissKeyguardRequestWithoutImmediateDismissAction).isEqualTo(Unit)
+ }
+
+ @Test
+ fun keyguardDone() =
+ testScope.runTest {
+ val keyguardDone by collectLastValue(underTest.keyguardDone)
+ assertThat(keyguardDone).isNull()
+
+ underTest.setKeyguardDone(KeyguardDone.IMMEDIATE)
+ assertThat(keyguardDone).isEqualTo(KeyguardDone.IMMEDIATE)
+
+ underTest.setKeyguardDone(KeyguardDone.LATER)
+ assertThat(keyguardDone).isEqualTo(KeyguardDone.LATER)
+ }
+
+ @Test
+ fun userRequestedBouncerWhenAlreadyAuthenticated_dismissActionRunImmediately() =
+ testScope.runTest {
+ val dismissKeyguardRequestWithoutImmediateDismissAction by
+ collectLastValue(underTest.dismissKeyguardRequestWithoutImmediateDismissAction)
+ val dismissKeyguardRequestWithImmediateDismissAction by
+ collectLastValue(underTest.dismissKeyguardRequestWithImmediateDismissAction)
+ underTestDependencies.userRepository.setSelectedUserInfo(userInfo)
+ runCurrent()
+
+ underTestDependencies.keyguardRepository.setDismissAction(
+ DismissAction.RunImmediately(
+ onDismissAction = { KeyguardDone.IMMEDIATE },
+ onCancelAction = {},
+ message = "",
+ willAnimateOnLockscreen = true,
+ )
+ )
+ underTestDependencies.bouncerRepository.setUserRequestedBouncerWhenAlreadyAuthenticated(
+ userInfo.id
+ )
+ assertThat(dismissKeyguardRequestWithoutImmediateDismissAction).isNull()
+ assertThat(dismissKeyguardRequestWithImmediateDismissAction).isEqualTo(Unit)
+ }
+
+ @Test
+ fun userRequestedBouncerWhenAlreadyAuthenticated_dismissActionRunAfterKeyguardGone() =
+ testScope.runTest {
+ val dismissKeyguardRequestWithImmediateWithoutDismissAction by
+ collectLastValue(underTest.dismissKeyguardRequestWithoutImmediateDismissAction)
+ val dismissKeyguardRequestWithImmediateDismissAction by
+ collectLastValue(underTest.dismissKeyguardRequestWithImmediateDismissAction)
+ underTestDependencies.userRepository.setSelectedUserInfo(userInfo)
+ runCurrent()
+
+ underTestDependencies.keyguardRepository.setDismissAction(
+ DismissAction.RunAfterKeyguardGone(
+ dismissAction = {},
+ onCancelAction = {},
+ message = "",
+ willAnimateOnLockscreen = true,
+ )
+ )
+ underTestDependencies.bouncerRepository.setUserRequestedBouncerWhenAlreadyAuthenticated(
+ userInfo.id
+ )
+ assertThat(dismissKeyguardRequestWithImmediateDismissAction).isNull()
+ assertThat(dismissKeyguardRequestWithImmediateWithoutDismissAction).isEqualTo(Unit)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index 904662e..da372ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -22,7 +22,10 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.coroutines.collectValues
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.ScrimAlpha
@@ -32,6 +35,7 @@
import com.android.systemui.util.mockito.whenever
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
@@ -47,13 +51,21 @@
class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
private lateinit var underTest: PrimaryBouncerToGoneTransitionViewModel
private lateinit var repository: FakeKeyguardTransitionRepository
+ private lateinit var featureFlags: FakeFeatureFlags
@Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
@Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ @Mock
+ private lateinit var keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
repository = FakeKeyguardTransitionRepository()
+ val featureFlags =
+ FakeFeatureFlags().apply {
+ set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)
+ set(Flags.UDFPS_NEW_TOUCH_DETECTION, true)
+ }
val interactor =
KeyguardTransitionInteractorFactory.create(
scope = TestScope().backgroundScope,
@@ -64,7 +76,9 @@
PrimaryBouncerToGoneTransitionViewModel(
interactor,
statusBarStateController,
- primaryBouncerInteractor
+ primaryBouncerInteractor,
+ keyguardDismissActionInteractor,
+ featureFlags,
)
whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false)
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 cbfad56..48a36cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -30,6 +30,8 @@
import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -93,7 +95,6 @@
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationShadeWindowView;
-import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -330,6 +331,58 @@
}
@Test
+ public void onHomeTouch_isRinging_keyguardShowing_touchBlocked() {
+ when(mTelecomManager.isRinging()).thenReturn(true);
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+ boolean result = mNavigationBar.onHomeTouch(
+ mNavigationBar.getView(),
+ MotionEvent.obtain(
+ /*downTime=*/SystemClock.uptimeMillis(),
+ /*eventTime=*/SystemClock.uptimeMillis(),
+ /*action=*/MotionEvent.ACTION_DOWN,
+ 0, 0, 0));
+
+ assertThat(result).isTrue();
+
+ // Verify subsequent touches are also blocked
+ boolean nextTouchEvent = mNavigationBar.onHomeTouch(
+ mNavigationBar.getView(),
+ MotionEvent.obtain(
+ /*downTime=*/SystemClock.uptimeMillis(),
+ /*eventTime=*/SystemClock.uptimeMillis(),
+ /*action=*/MotionEvent.ACTION_MOVE,
+ 0, 0, 0));
+ assertThat(nextTouchEvent).isTrue();
+ }
+
+ @Test
+ public void onHomeTouch_isRinging_keyguardNotShowing_touchNotBlocked() {
+ when(mTelecomManager.isRinging()).thenReturn(true);
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+
+ boolean result = mNavigationBar.onHomeTouch(
+ mNavigationBar.getView(),
+ MotionEvent.obtain(
+ /*downTime=*/SystemClock.uptimeMillis(),
+ /*eventTime=*/SystemClock.uptimeMillis(),
+ /*action=*/MotionEvent.ACTION_DOWN,
+ 0, 0, 0));
+
+ assertThat(result).isFalse();
+
+ // Verify subsequent touches are also not blocked
+ boolean nextTouchEvent = mNavigationBar.onHomeTouch(
+ mNavigationBar.getView(),
+ MotionEvent.obtain(
+ /*downTime=*/SystemClock.uptimeMillis(),
+ /*eventTime=*/SystemClock.uptimeMillis(),
+ /*action=*/MotionEvent.ACTION_MOVE,
+ 0, 0, 0));
+ assertThat(nextTouchEvent).isFalse();
+ }
+
+ @Test
public void testRegisteredWithUserTracker() {
mNavigationBar.init();
mNavigationBar.onViewAttached();
@@ -468,7 +521,6 @@
when(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
return spy(new NavigationBar(
mNavigationBarView,
- mock(ShadeController.class),
mNavigationBarFrame,
null,
context,
@@ -487,6 +539,7 @@
Optional.of(mock(Pip.class)),
Optional.of(mock(Recents.class)),
() -> Optional.of(mCentralSurfaces),
+ mKeyguardStateController,
mock(ShadeViewController.class),
mock(NotificationRemoteInputManager.class),
mock(NotificationShadeDepthController.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 1c9ec27..4f57fd0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -65,6 +65,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardClockSwitchController;
@@ -271,6 +272,7 @@
@Mock protected KeyguardIndicationController mKeyguardIndicationController;
@Mock protected FragmentService mFragmentService;
@Mock protected FragmentHostManager mFragmentHostManager;
+ @Mock protected IStatusBarService mStatusBarService;
@Mock protected NotificationRemoteInputManager mNotificationRemoteInputManager;
@Mock protected RecordingController mRecordingController;
@Mock protected LockscreenGestureLogger mLockscreenGestureLogger;
@@ -621,6 +623,7 @@
mNavigationBarController,
mQsController,
mFragmentService,
+ mStatusBarService,
mContentResolver,
mShadeHeaderController,
mScreenOffAnimationController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
index 2e5afa4..98315d0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
@@ -18,6 +18,8 @@
import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
+import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_DENIED;
+import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
@@ -439,11 +441,29 @@
public void setVoiceRegState(int voiceRegState) {
when(mServiceState.getState()).thenReturn(voiceRegState);
+ when(mServiceState.getVoiceRegState()).thenReturn(voiceRegState);
updateServiceState();
}
- public void setDataRegState(int dataRegState) {
- when(mServiceState.getDataRegistrationState()).thenReturn(dataRegState);
+ public void setDataRegInService(boolean inService) {
+ // mFakeRegInfo#isInService()
+ // Utils#isInService uses NetworkRegistrationInfo#isInService(). Since we can't
+ // mock the answer here, just set the bit based on what the caller wants
+ NetworkRegistrationInfo.Builder builder = new NetworkRegistrationInfo.Builder()
+ .setTransportType(TRANSPORT_TYPE_WWAN)
+ .setDomain(DOMAIN_PS)
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE);
+
+ if (inService) {
+ builder.setRegistrationState(REGISTRATION_STATE_HOME);
+ } else {
+ builder.setRegistrationState(REGISTRATION_STATE_DENIED);
+ }
+
+ NetworkRegistrationInfo fakeRegInfo = builder.build();
+ when(mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN))
+ .thenReturn(fakeRegInfo);
+
updateServiceState();
}
@@ -658,3 +678,4 @@
assertEquals("Data network name", expected, mNetworkController.getMobileDataNetworkName());
}
}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
index d5689dc..f667b83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
@@ -340,7 +340,7 @@
public void testIsDataInService_notInService_false() {
setupDefaultSignal();
setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
- setDataRegState(ServiceState.STATE_OUT_OF_SERVICE);
+ setDataRegInService(false);
assertFalse(mNetworkController.isMobileDataNetworkInService());
}
@@ -408,3 +408,4 @@
false);
}
}
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 0da7360..798c3f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -18,7 +18,6 @@
import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
-
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -34,7 +33,6 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-
import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
import android.service.trust.TrustAgentService;
@@ -73,8 +71,9 @@
import com.android.systemui.bouncer.ui.BouncerViewDelegate;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -131,7 +130,7 @@
@Mock private SysUIUnfoldComponent mSysUiUnfoldComponent;
@Mock private DreamOverlayStateController mDreamOverlayStateController;
@Mock private LatencyTracker mLatencyTracker;
- @Mock private FeatureFlags mFeatureFlags;
+ private FakeFeatureFlags mFeatureFlags;
@Mock private KeyguardSecurityModel mKeyguardSecurityModel;
@Mock private PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
@Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@@ -171,9 +170,11 @@
.thenReturn(mKeyguardMessageAreaController);
when(mBouncerView.getDelegate()).thenReturn(mBouncerViewDelegate);
when(mBouncerViewDelegate.getBackCallback()).thenReturn(mBouncerViewDelegateBackCallback);
- when(mFeatureFlags
- .isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM))
- .thenReturn(true);
+ mFeatureFlags = new FakeFeatureFlags();
+ mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM, true);
+ mFeatureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false);
+ mFeatureFlags.set(Flags.UDFPS_NEW_TOUCH_DETECTION, true);
+ mFeatureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false);
when(mNotificationShadeWindowController.getWindowRootView())
.thenReturn(mNotificationShadeWindowView);
@@ -208,7 +209,8 @@
mActivityStarter,
mock(KeyguardTransitionInteractor.class),
StandardTestDispatcher(null, null),
- () -> mock(WindowManagerLockscreenVisibilityInteractor.class)) {
+ () -> mock(WindowManagerLockscreenVisibilityInteractor.class),
+ () -> mock(KeyguardDismissActionInteractor.class)) {
@Override
public ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
@@ -711,7 +713,8 @@
mActivityStarter,
mock(KeyguardTransitionInteractor.class),
StandardTestDispatcher(null, null),
- () -> mock(WindowManagerLockscreenVisibilityInteractor.class)) {
+ () -> mock(WindowManagerLockscreenVisibilityInteractor.class),
+ () -> mock(KeyguardDismissActionInteractor.class)) {
@Override
public ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index 3af960b..8ef82c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -19,8 +19,13 @@
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
+import android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN
+import android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN
import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
import android.telephony.NetworkRegistrationInfo
+import android.telephony.NetworkRegistrationInfo.DOMAIN_PS
+import android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_DENIED
+import android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME
import android.telephony.ServiceState
import android.telephony.ServiceState.STATE_IN_SERVICE
import android.telephony.ServiceState.STATE_OUT_OF_SERVICE
@@ -80,7 +85,6 @@
import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
-import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -801,11 +805,18 @@
var latest: Boolean? = null
val job = underTest.isInService.onEach { latest = it }.launchIn(this)
+ val nriInService =
+ NetworkRegistrationInfo.Builder()
+ .setDomain(DOMAIN_PS)
+ .setTransportType(TRANSPORT_TYPE_WWAN)
+ .setRegistrationState(REGISTRATION_STATE_HOME)
+ .build()
+
getTelephonyCallbackForType<ServiceStateListener>()
.onServiceStateChanged(
ServiceState().also {
it.voiceRegState = STATE_IN_SERVICE
- it.dataRegState = STATE_IN_SERVICE
+ it.addNetworkRegistrationInfo(nriInService)
}
)
@@ -814,17 +825,23 @@
getTelephonyCallbackForType<ServiceStateListener>()
.onServiceStateChanged(
ServiceState().also {
- it.dataRegState = STATE_IN_SERVICE
it.voiceRegState = STATE_OUT_OF_SERVICE
+ it.addNetworkRegistrationInfo(nriInService)
}
)
assertThat(latest).isTrue()
+ val nriNotInService =
+ NetworkRegistrationInfo.Builder()
+ .setDomain(DOMAIN_PS)
+ .setTransportType(TRANSPORT_TYPE_WWAN)
+ .setRegistrationState(REGISTRATION_STATE_DENIED)
+ .build()
getTelephonyCallbackForType<ServiceStateListener>()
.onServiceStateChanged(
ServiceState().also {
it.voiceRegState = STATE_OUT_OF_SERVICE
- it.dataRegState = STATE_OUT_OF_SERVICE
+ it.addNetworkRegistrationInfo(nriNotInService)
}
)
assertThat(latest).isFalse()
@@ -838,18 +855,17 @@
var latest: Boolean? = null
val job = underTest.isInService.onEach { latest = it }.launchIn(this)
- // Mock the service state here so we can make it specifically IWLAN
- val serviceState: ServiceState = mock()
- whenever(serviceState.state).thenReturn(STATE_OUT_OF_SERVICE)
- whenever(serviceState.dataRegistrationState).thenReturn(STATE_IN_SERVICE)
-
- // See [com.android.settingslib.Utils.isInService] for more info. This is one way to
- // make the network look like IWLAN
- val networkRegWlan: NetworkRegistrationInfo = mock()
- whenever(serviceState.getNetworkRegistrationInfo(any(), any()))
- .thenReturn(networkRegWlan)
- whenever(networkRegWlan.registrationState)
- .thenReturn(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+ val iwlanData =
+ NetworkRegistrationInfo.Builder()
+ .setDomain(DOMAIN_PS)
+ .setTransportType(TRANSPORT_TYPE_WLAN)
+ .setRegistrationState(REGISTRATION_STATE_HOME)
+ .build()
+ val serviceState =
+ ServiceState().also {
+ it.voiceRegState = STATE_OUT_OF_SERVICE
+ it.addNetworkRegistrationInfo(iwlanData)
+ }
getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
assertThat(latest).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index 243f881..e761635 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -46,8 +46,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.bluetooth.BluetoothLogger;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.bluetooth.BluetoothRepository;
import com.android.systemui.statusbar.policy.bluetooth.FakeBluetoothRepository;
@@ -75,8 +73,6 @@
private DumpManager mMockDumpManager;
private BluetoothControllerImpl mBluetoothControllerImpl;
private BluetoothAdapter mMockAdapter;
- private final FakeFeatureFlags mFakeFeatureFlags = new FakeFeatureFlags();
-
private List<CachedBluetoothDevice> mDevices;
@Before
@@ -98,11 +94,9 @@
BluetoothRepository bluetoothRepository =
new FakeBluetoothRepository(mMockBluetoothManager);
- mFakeFeatureFlags.set(Flags.NEW_BLUETOOTH_REPOSITORY, true);
mBluetoothControllerImpl = new BluetoothControllerImpl(
mContext,
- mFakeFeatureFlags,
mUserTracker,
mMockDumpManager,
mock(BluetoothLogger.class),
@@ -111,27 +105,8 @@
mMockBluetoothManager,
mMockAdapter);
}
-
@Test
- public void testNoConnectionWithDevices_repoFlagOff() {
- mFakeFeatureFlags.set(Flags.NEW_BLUETOOTH_REPOSITORY, false);
-
- CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
- when(device.isConnected()).thenReturn(true);
- when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED);
- mDevices.add(device);
- when(mMockLocalAdapter.getConnectionState())
- .thenReturn(BluetoothAdapter.STATE_DISCONNECTED);
-
- mBluetoothControllerImpl.onConnectionStateChanged(null,
- BluetoothAdapter.STATE_DISCONNECTED);
- assertTrue(mBluetoothControllerImpl.isBluetoothConnected());
- }
-
- @Test
- public void testNoConnectionWithDevices_repoFlagOn() {
- mFakeFeatureFlags.set(Flags.NEW_BLUETOOTH_REPOSITORY, true);
-
+ public void testNoConnectionWithDevices() {
CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
when(device.isConnected()).thenReturn(true);
when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED);
@@ -147,9 +122,7 @@
}
@Test
- public void testOnServiceConnected_updatesConnectionState_repoFlagOff() {
- mFakeFeatureFlags.set(Flags.NEW_BLUETOOTH_REPOSITORY, false);
-
+ public void testOnServiceConnected_updatesConnectionState() {
when(mMockLocalAdapter.getConnectionState()).thenReturn(BluetoothAdapter.STATE_CONNECTING);
mBluetoothControllerImpl.onServiceConnected();
@@ -159,41 +132,7 @@
}
@Test
- public void testOnServiceConnected_updatesConnectionState_repoFlagOn() {
- mFakeFeatureFlags.set(Flags.NEW_BLUETOOTH_REPOSITORY, true);
-
- when(mMockLocalAdapter.getConnectionState()).thenReturn(BluetoothAdapter.STATE_CONNECTING);
-
- mBluetoothControllerImpl.onServiceConnected();
-
- assertTrue(mBluetoothControllerImpl.isBluetoothConnecting());
- assertFalse(mBluetoothControllerImpl.isBluetoothConnected());
- }
-
- @Test
- public void getConnectedDevices_onlyReturnsConnected_repoFlagOff() {
- mFakeFeatureFlags.set(Flags.NEW_BLUETOOTH_REPOSITORY, false);
-
- CachedBluetoothDevice device1Disconnected = mock(CachedBluetoothDevice.class);
- when(device1Disconnected.isConnected()).thenReturn(false);
- mDevices.add(device1Disconnected);
-
- CachedBluetoothDevice device2Connected = mock(CachedBluetoothDevice.class);
- when(device2Connected.isConnected()).thenReturn(true);
- mDevices.add(device2Connected);
-
- mBluetoothControllerImpl.onDeviceAdded(device1Disconnected);
- mBluetoothControllerImpl.onDeviceAdded(device2Connected);
-
- assertThat(mBluetoothControllerImpl.getConnectedDevices()).hasSize(1);
- assertThat(mBluetoothControllerImpl.getConnectedDevices().get(0))
- .isEqualTo(device2Connected);
- }
-
- @Test
- public void getConnectedDevices_onlyReturnsConnected_repoFlagOn() {
- mFakeFeatureFlags.set(Flags.NEW_BLUETOOTH_REPOSITORY, true);
-
+ public void getConnectedDevices_onlyReturnsConnected() {
CachedBluetoothDevice device1Disconnected = mock(CachedBluetoothDevice.class);
when(device1Disconnected.isConnected()).thenReturn(false);
mDevices.add(device1Disconnected);
@@ -235,31 +174,7 @@
}
@Test
- public void testOnACLConnectionStateChange_updatesBluetoothStateOnConnection_repoFlagOff() {
- mFakeFeatureFlags.set(Flags.NEW_BLUETOOTH_REPOSITORY, false);
-
- BluetoothController.Callback callback = mock(BluetoothController.Callback.class);
- mBluetoothControllerImpl.addCallback(callback);
-
- assertFalse(mBluetoothControllerImpl.isBluetoothConnected());
- CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
- mDevices.add(device);
- when(device.isConnected()).thenReturn(true);
- when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED);
- reset(callback);
- mBluetoothControllerImpl.onAclConnectionStateChanged(device,
- BluetoothProfile.STATE_CONNECTED);
-
- mTestableLooper.processAllMessages();
-
- assertTrue(mBluetoothControllerImpl.isBluetoothConnected());
- verify(callback, atLeastOnce()).onBluetoothStateChange(anyBoolean());
- }
-
- @Test
- public void testOnACLConnectionStateChange_updatesBluetoothStateOnConnection_repoFlagOn() {
- mFakeFeatureFlags.set(Flags.NEW_BLUETOOTH_REPOSITORY, true);
-
+ public void testOnACLConnectionStateChange_updatesBluetoothStateOnConnection() {
BluetoothController.Callback callback = mock(BluetoothController.Callback.class);
mBluetoothControllerImpl.addCallback(callback);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
index 7c98df6..f2e4528 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
@@ -51,6 +51,8 @@
override val authenticationMethod: StateFlow<AuthenticationMethodModel> =
_authenticationMethod.asStateFlow()
+ override val minPatternLength: Int = 4
+
private var isLockscreenEnabled = true
private var failedAttemptCount = 0
private var throttlingEndTimestamp = 0L
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
index 0847c85..b45c198 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
@@ -2,11 +2,14 @@
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
-/** Fake implementation of [KeyguardRepository] */
+/** Fake implementation of [KeyguardBouncerRepository] */
class FakeKeyguardBouncerRepository : KeyguardBouncerRepository {
private val _primaryBouncerShow = MutableStateFlow(false)
override val primaryBouncerShow = _primaryBouncerShow.asStateFlow()
@@ -26,7 +29,13 @@
private val _isBackButtonEnabled = MutableStateFlow<Boolean?>(null)
override val isBackButtonEnabled = _isBackButtonEnabled.asStateFlow()
private val _keyguardAuthenticated = MutableStateFlow<Boolean?>(null)
- override val keyguardAuthenticated = _keyguardAuthenticated.asStateFlow()
+ override val keyguardAuthenticatedBiometrics = _keyguardAuthenticated.asStateFlow()
+ private val _keyguardAuthenticatedPrimaryAuth = MutableSharedFlow<Int>()
+ override val keyguardAuthenticatedPrimaryAuth: Flow<Int> =
+ _keyguardAuthenticatedPrimaryAuth.asSharedFlow()
+ private val _userRequestedBouncerWhenAlreadyAuthenticated = MutableSharedFlow<Int>()
+ override val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Int> =
+ _userRequestedBouncerWhenAlreadyAuthenticated.asSharedFlow()
private val _showMessage = MutableStateFlow<BouncerShowMessageModel?>(null)
override val showMessage = _showMessage.asStateFlow()
private val _resourceUpdateRequests = MutableStateFlow(false)
@@ -83,10 +92,18 @@
_showMessage.value = bouncerShowMessageModel
}
- override fun setKeyguardAuthenticated(keyguardAuthenticated: Boolean?) {
+ override fun setKeyguardAuthenticatedBiometrics(keyguardAuthenticated: Boolean?) {
_keyguardAuthenticated.value = keyguardAuthenticated
}
+ override suspend fun setKeyguardAuthenticatedPrimaryAuth(userId: Int) {
+ _keyguardAuthenticatedPrimaryAuth.emit(userId)
+ }
+
+ override suspend fun setUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int) {
+ _userRequestedBouncerWhenAlreadyAuthenticated.emit(userId)
+ }
+
override fun setIsBackButtonEnabled(isBackButtonEnabled: Boolean) {
_isBackButtonEnabled.value = isBackButtonEnabled
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index cc0c943..dae8644 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -21,7 +21,9 @@
import com.android.systemui.common.shared.model.Position
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
+import com.android.systemui.keyguard.shared.model.DismissAction
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
+import com.android.systemui.keyguard.shared.model.KeyguardDone
import com.android.systemui.keyguard.shared.model.KeyguardRootViewVisibilityState
import com.android.systemui.keyguard.shared.model.ScreenModel
import com.android.systemui.keyguard.shared.model.ScreenState
@@ -30,12 +32,18 @@
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
/** Fake implementation of [KeyguardRepository] */
class FakeKeyguardRepository : KeyguardRepository {
+ private val _deferKeyguardDone: MutableSharedFlow<KeyguardDone> = MutableSharedFlow()
+ override val keyguardDone: Flow<KeyguardDone> = _deferKeyguardDone
+
+ private val _dismissAction = MutableStateFlow<DismissAction>(DismissAction.None)
+ override val dismissAction: StateFlow<DismissAction> = _dismissAction
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions: StateFlow<Boolean> =
@@ -175,6 +183,14 @@
_dozeTimeTick.value = _dozeTimeTick.value + 1
}
+ override fun setDismissAction(dismissAction: DismissAction) {
+ _dismissAction.value = dismissAction
+ }
+
+ override suspend fun setKeyguardDone(timing: KeyguardDone) {
+ _deferKeyguardDone.emit(timing)
+ }
+
fun dozeTimeTick(millis: Long) {
_dozeTimeTick.value = millis
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
index 817e1db..9d98f94 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
@@ -17,6 +17,8 @@
package com.android.systemui.keyguard.data.repository
+import com.android.keyguard.TrustGrantFlags
+import com.android.systemui.keyguard.shared.model.TrustModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -35,6 +37,9 @@
override val isCurrentUserTrustManaged: StateFlow<Boolean>
get() = _isCurrentUserTrustManaged
+ private val _requestDismissKeyguard = MutableStateFlow(TrustModel(false, 0, TrustGrantFlags(0)))
+ override val trustAgentRequestingToDismissKeyguard: Flow<TrustModel> = _requestDismissKeyguard
+
fun setCurrentUserTrusted(trust: Boolean) {
_isCurrentUserTrusted.value = trust
}
@@ -46,4 +51,8 @@
fun setCurrentUserActiveUnlockAvailable(available: Boolean) {
_isCurrentUserActiveUnlockAvailable.value = available
}
+
+ fun setRequestDismissKeyguard(trustModel: TrustModel) {
+ _requestDismissKeyguard.value = trustModel
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
new file mode 100644
index 0000000..6dd41f4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.app.ActivityManager
+import android.content.Context
+import android.os.Handler
+import android.os.UserManager
+import com.android.internal.logging.UiEventLogger
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.broadcast.FakeBroadcastDispatcher
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
+import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.domain.interactor.GuestUserInteractor
+import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
+import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.util.time.FakeSystemClock
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.test.TestScope
+import org.mockito.Mockito.mock
+
+/**
+ * Helper to create a new KeyguardDismissInteractor in a way that doesn't require modifying many
+ * tests whenever we add a constructor param.
+ */
+object KeyguardDismissInteractorFactory {
+ @JvmOverloads
+ @JvmStatic
+ fun create(
+ context: Context,
+ testScope: TestScope,
+ broadcastDispatcher: FakeBroadcastDispatcher,
+ dispatcher: CoroutineDispatcher,
+ trustRepository: FakeTrustRepository = FakeTrustRepository(),
+ keyguardRepository: FakeKeyguardRepository = FakeKeyguardRepository(),
+ bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(),
+ keyguardUpdateMonitor: KeyguardUpdateMonitor = mock(KeyguardUpdateMonitor::class.java),
+ featureFlags: FakeFeatureFlagsClassic =
+ FakeFeatureFlagsClassic().apply {
+ set(Flags.DELAY_BOUNCER, true)
+ set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, true)
+ set(Flags.FULL_SCREEN_USER_SWITCHER, false)
+ },
+ powerRepository: FakePowerRepository = FakePowerRepository(),
+ userRepository: FakeUserRepository = FakeUserRepository(),
+ ): WithDependencies {
+ val primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ context,
+ keyguardUpdateMonitor,
+ trustRepository,
+ featureFlags,
+ testScope.backgroundScope,
+ )
+ val alternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ mock(StatusBarStateController::class.java),
+ mock(KeyguardStateController::class.java),
+ bouncerRepository,
+ FakeBiometricSettingsRepository(),
+ FakeSystemClock(),
+ keyguardUpdateMonitor,
+ )
+ val powerInteractor =
+ PowerInteractor(
+ powerRepository,
+ keyguardRepository,
+ mock(FalsingCollector::class.java),
+ mock(ScreenOffAnimationController::class.java),
+ mock(StatusBarStateController::class.java),
+ )
+ val userInteractor =
+ UserInteractor(
+ applicationContext = context,
+ repository = userRepository,
+ mock(ActivityStarter::class.java),
+ keyguardInteractor =
+ KeyguardInteractorFactory.create(
+ repository = keyguardRepository,
+ bouncerRepository = bouncerRepository,
+ featureFlags = featureFlags,
+ )
+ .keyguardInteractor,
+ featureFlags = featureFlags,
+ manager = mock(UserManager::class.java),
+ headlessSystemUserMode = mock(HeadlessSystemUserMode::class.java),
+ applicationScope = testScope.backgroundScope,
+ telephonyInteractor =
+ TelephonyInteractor(
+ repository = FakeTelephonyRepository(),
+ ),
+ broadcastDispatcher = broadcastDispatcher,
+ keyguardUpdateMonitor = keyguardUpdateMonitor,
+ backgroundDispatcher = dispatcher,
+ activityManager = mock(ActivityManager::class.java),
+ refreshUsersScheduler = mock(RefreshUsersScheduler::class.java),
+ guestUserInteractor = mock(GuestUserInteractor::class.java),
+ uiEventLogger = mock(UiEventLogger::class.java),
+ )
+ return WithDependencies(
+ trustRepository = trustRepository,
+ keyguardRepository = keyguardRepository,
+ bouncerRepository = bouncerRepository,
+ keyguardUpdateMonitor = keyguardUpdateMonitor,
+ powerRepository = powerRepository,
+ userRepository = userRepository,
+ interactor =
+ KeyguardDismissInteractor(
+ trustRepository,
+ keyguardRepository,
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ powerInteractor,
+ userInteractor,
+ ),
+ )
+ }
+
+ data class WithDependencies(
+ val trustRepository: FakeTrustRepository,
+ val keyguardRepository: FakeKeyguardRepository,
+ val bouncerRepository: FakeKeyguardBouncerRepository,
+ val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ val powerRepository: FakePowerRepository,
+ val userRepository: FakeUserRepository,
+ val interactor: KeyguardDismissInteractor,
+ )
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 70382f1..4488d86 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -443,7 +443,8 @@
}
final BatchUpdates batchUpdates = pair.second;
// First apply the updates...
- final RemoteViews templateUpdates = batchUpdates.getUpdates();
+ final RemoteViews templateUpdates =
+ Helper.sanitizeRemoteView(batchUpdates.getUpdates());
if (templateUpdates != null) {
if (sDebug) Slog.d(TAG, "Applying template updates for batch update #" + i);
templateUpdates.reapply(context, customSubtitleView);
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 05327dc..a792db0 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -738,6 +738,9 @@
try {
String transportName = transport.name();
String transportDirName = transport.transportDirName();
+ if (transportName == null || transportDirName == null) {
+ return BackupManager.ERROR_TRANSPORT_INVALID;
+ }
registerTransport(transportComponent, transport);
// If registerTransport() hasn't thrown...
Slog.d(TAG, addUserIdToLogMessage(mUserId, "Transport " + transportString
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 1ce7d96..330e35b 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -74,6 +74,7 @@
import android.companion.IOnMessageReceivedListener;
import android.companion.IOnTransportsChangedListener;
import android.companion.ISystemDataTransferCallback;
+import android.companion.datatransfer.PermissionSyncRequest;
import android.companion.utils.FeatureUtils;
import android.content.ComponentName;
import android.content.Context;
@@ -873,6 +874,24 @@
}
@Override
+ public void enablePermissionsSync(int associationId) {
+ getAssociationWithCallerChecks(associationId);
+ mSystemDataTransferProcessor.enablePermissionsSync(associationId);
+ }
+
+ @Override
+ public void disablePermissionsSync(int associationId) {
+ getAssociationWithCallerChecks(associationId);
+ mSystemDataTransferProcessor.disablePermissionsSync(associationId);
+ }
+
+ @Override
+ public PermissionSyncRequest getPermissionSyncRequest(int associationId) {
+ getAssociationWithCallerChecks(associationId);
+ return mSystemDataTransferProcessor.getPermissionSyncRequest(associationId);
+ }
+
+ @Override
@EnforcePermission(MANAGE_COMPANION_DEVICES)
public void enableSecureTransport(boolean enabled) {
enableSecureTransport_enforcePermission();
@@ -1041,7 +1060,7 @@
String[] args, ShellCallback callback, ResultReceiver resultReceiver)
throws RemoteException {
new CompanionDeviceShellCommand(CompanionDeviceManagerService.this, mAssociationStore,
- mDevicePresenceMonitor, mTransportManager, mSystemDataTransferRequestStore,
+ mDevicePresenceMonitor, mTransportManager, mSystemDataTransferProcessor,
mAssociationRequestsProcessor)
.exec(this, in, out, err, args, callback, resultReceiver);
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index d368b86..1f62613 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -27,7 +27,7 @@
import android.os.ShellCommand;
import android.util.proto.ProtoOutputStream;
-import com.android.server.companion.datatransfer.SystemDataTransferRequestStore;
+import com.android.server.companion.datatransfer.SystemDataTransferProcessor;
import com.android.server.companion.datatransfer.contextsync.BitmapUtils;
import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController;
import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
@@ -44,20 +44,20 @@
private final CompanionDevicePresenceMonitor mDevicePresenceMonitor;
private final CompanionTransportManager mTransportManager;
- private final SystemDataTransferRequestStore mSystemDataTransferRequestStore;
+ private final SystemDataTransferProcessor mSystemDataTransferProcessor;
private final AssociationRequestsProcessor mAssociationRequestsProcessor;
CompanionDeviceShellCommand(CompanionDeviceManagerService service,
AssociationStoreImpl associationStore,
CompanionDevicePresenceMonitor devicePresenceMonitor,
CompanionTransportManager transportManager,
- SystemDataTransferRequestStore systemDataTransferRequestStore,
+ SystemDataTransferProcessor systemDataTransferProcessor,
AssociationRequestsProcessor associationRequestsProcessor) {
mService = service;
mAssociationStore = associationStore;
mDevicePresenceMonitor = devicePresenceMonitor;
mTransportManager = transportManager;
- mSystemDataTransferRequestStore = systemDataTransferRequestStore;
+ mSystemDataTransferProcessor = systemDataTransferProcessor;
mAssociationRequestsProcessor = associationRequestsProcessor;
}
@@ -261,16 +261,47 @@
break;
}
- case "allow-permission-sync": {
- int userId = getNextIntArgRequired();
+ case "get-perm-sync-state": {
associationId = getNextIntArgRequired();
- boolean enabled = getNextBooleanArgRequired();
- PermissionSyncRequest request = new PermissionSyncRequest(associationId);
- request.setUserId(userId);
- request.setUserConsented(enabled);
- mSystemDataTransferRequestStore.writeRequest(userId, request);
+ PermissionSyncRequest request =
+ mSystemDataTransferProcessor.getPermissionSyncRequest(associationId);
+ out.println((request == null ? "null" : request.isUserConsented()));
+ break;
}
- break;
+
+ case "remove-perm-sync-state": {
+ associationId = getNextIntArgRequired();
+ PermissionSyncRequest request =
+ mSystemDataTransferProcessor.getPermissionSyncRequest(associationId);
+ out.print((request == null ? "null" : request.isUserConsented()));
+ mSystemDataTransferProcessor.removePermissionSyncRequest(associationId);
+ request = mSystemDataTransferProcessor.getPermissionSyncRequest(associationId);
+ // should print " -> null"
+ out.println(" -> " + (request == null ? "null" : request.isUserConsented()));
+ break;
+ }
+
+ case "enable-perm-sync": {
+ associationId = getNextIntArgRequired();
+ PermissionSyncRequest request =
+ mSystemDataTransferProcessor.getPermissionSyncRequest(associationId);
+ out.print((request == null ? "null" : request.isUserConsented()));
+ mSystemDataTransferProcessor.enablePermissionsSync(associationId);
+ request = mSystemDataTransferProcessor.getPermissionSyncRequest(associationId);
+ out.println(" -> " + request.isUserConsented()); // should print " -> true"
+ break;
+ }
+
+ case "disable-perm-sync": {
+ associationId = getNextIntArgRequired();
+ PermissionSyncRequest request =
+ mSystemDataTransferProcessor.getPermissionSyncRequest(associationId);
+ out.print((request == null ? "null" : request.isUserConsented()));
+ mSystemDataTransferProcessor.disablePermissionsSync(associationId);
+ request = mSystemDataTransferProcessor.getPermissionSyncRequest(associationId);
+ out.println(" -> " + request.isUserConsented()); // should print " -> false"
+ break;
+ }
default:
return handleDefaultCommands(cmd);
@@ -346,5 +377,14 @@
pw.println(" create-emulated-transport <ASSOCIATION_ID>");
pw.println(" Create an EmulatedTransport for testing purposes only");
+
+ pw.println(" enable-perm-sync <ASSOCIATION_ID>");
+ pw.println(" Enable perm sync for the association.");
+ pw.println(" disable-perm-sync <ASSOCIATION_ID>");
+ pw.println(" Disable perm sync for the association.");
+ pw.println(" get-perm-sync-state <ASSOCIATION_ID>");
+ pw.println(" Get perm sync state for the association.");
+ pw.println(" remove-perm-sync-state <ASSOCIATION_ID>");
+ pw.println(" Remove perm sync state for the association.");
}
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
index 13f41ed..42b5a8b 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -139,6 +139,13 @@
@UserIdInt int userId, int associationId) {
if (PackageUtils.isPackageAllowlisted(mContext, mPackageManager, packageName)) {
Slog.i(LOG_TAG, "User consent Intent should be skipped. Returning null.");
+ // Auto enable perm sync for the whitelisted packages, but don't override user decision
+ PermissionSyncRequest request = getPermissionSyncRequest(associationId);
+ if (request == null) {
+ PermissionSyncRequest newRequest = new PermissionSyncRequest(associationId);
+ newRequest.setUserConsented(true);
+ mSystemDataTransferRequestStore.writeRequest(userId, newRequest);
+ }
return null;
}
@@ -185,29 +192,17 @@
final AssociationInfo association = resolveAssociation(packageName, userId, associationId);
// Check if the request has been consented by the user.
- if (PackageUtils.isPackageAllowlisted(mContext, mPackageManager, packageName)) {
- Slog.i(LOG_TAG, "Skip user consent check due to the same OEM package.");
- } else {
- List<SystemDataTransferRequest> storedRequests =
- mSystemDataTransferRequestStore.readRequestsByAssociationId(userId,
- associationId);
- boolean hasConsented = false;
- for (SystemDataTransferRequest storedRequest : storedRequests) {
- if (storedRequest instanceof PermissionSyncRequest
- && storedRequest.isUserConsented()) {
- hasConsented = true;
- break;
- }
+ PermissionSyncRequest request = getPermissionSyncRequest(associationId);
+ if (request == null || !request.isUserConsented()) {
+ String message =
+ "User " + userId + " hasn't consented permission sync for associationId ["
+ + associationId + ".";
+ Slog.e(LOG_TAG, message);
+ try {
+ callback.onError(message);
+ } catch (RemoteException ignored) {
}
- if (!hasConsented) {
- String message = "User " + userId + " hasn't consented permission sync.";
- Slog.e(LOG_TAG, message);
- try {
- callback.onError(message);
- } catch (RemoteException ignored) {
- }
- return;
- }
+ return;
}
// Start permission sync
@@ -225,6 +220,50 @@
}
}
+ /**
+ * Enable perm sync for the association
+ */
+ public void enablePermissionsSync(int associationId) {
+ int userId = mAssociationStore.getAssociationById(associationId).getUserId();
+ PermissionSyncRequest request = new PermissionSyncRequest(associationId);
+ request.setUserConsented(true);
+ mSystemDataTransferRequestStore.writeRequest(userId, request);
+ }
+
+ /**
+ * Disable perm sync for the association
+ */
+ public void disablePermissionsSync(int associationId) {
+ int userId = mAssociationStore.getAssociationById(associationId).getUserId();
+ PermissionSyncRequest request = new PermissionSyncRequest(associationId);
+ request.setUserConsented(false);
+ mSystemDataTransferRequestStore.writeRequest(userId, request);
+ }
+
+ /**
+ * Get perm sync request for the association.
+ */
+ @Nullable
+ public PermissionSyncRequest getPermissionSyncRequest(int associationId) {
+ int userId = mAssociationStore.getAssociationById(associationId).getUserId();
+ List<SystemDataTransferRequest> requests =
+ mSystemDataTransferRequestStore.readRequestsByAssociationId(userId, associationId);
+ for (SystemDataTransferRequest request : requests) {
+ if (request instanceof PermissionSyncRequest) {
+ return (PermissionSyncRequest) request;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Remove perm sync request for the association.
+ */
+ public void removePermissionSyncRequest(int associationId) {
+ int userId = mAssociationStore.getAssociationById(associationId).getUserId();
+ mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, associationId);
+ }
+
private void onReceivePermissionRestore(byte[] message) {
Slog.i(LOG_TAG, "Applying permissions.");
// Start applying permissions
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
index 720cefa..9f489e8 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
@@ -104,7 +104,7 @@
}
@NonNull
- List<SystemDataTransferRequest> readRequestsByAssociationId(@UserIdInt int userId,
+ public List<SystemDataTransferRequest> readRequestsByAssociationId(@UserIdInt int userId,
int associationId) {
List<SystemDataTransferRequest> cachedRequests;
synchronized (mLock) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 8e538b2..d9c2694 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -193,6 +193,7 @@
"power_optimization_flags_lib",
"notification_flags_lib",
"camera_platform_flags_core_java_lib",
+ "biometrics_flags_lib",
],
javac_shard_size: 50,
javacflags: [
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index b79ba7ba..6d2fc0d 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -115,28 +115,47 @@
};
// All the aconfig flags under the listed DeviceConfig scopes will be synced to native level.
+ // The list is sorted.
@VisibleForTesting
static final String[] sDeviceConfigAconfigScopes = new String[] {
- "biometrics_framework",
- "core_experiments_team_internal",
- "camera_platform",
- "power",
- "vibrator",
- "haptics",
- "text",
+ "android_core_networking",
+ "angle",
"arc_next",
- "test_suites",
- "hardware_backed_security_mainline",
- "threadnetwork",
- "media_solutions",
- "responsible_apis",
- "rust",
- "pixel_biometrics",
+ "bluetooth",
+ "biometrics_framework",
+ "biometrics_integration",
+ "camera_platform",
+ "car_framework",
"car_perception",
"car_security",
"car_telemetry",
- "car_framework",
- "android-nfc",
+ "codec_fwk",
+ "companion",
+ "context_hub",
+ "core_experiments_team_internal",
+ "haptics",
+ "hardware_backed_security_mainline",
+ "media_audio",
+ "media_solutions",
+ "nfc",
+ "pixel_system_sw_touch",
+ "pixel_watch",
+ "platform_security",
+ "power",
+ "preload_safety",
+ "responsible_apis",
+ "rust",
+ "system_performance",
+ "test_suites",
+ "text",
+ "threadnetwork",
+ "tv_system_ui",
+ "vibrator",
+ "wear_frameworks",
+ "wear_system_health",
+ "wear_systems",
+ "window_surfaces",
+ "windowing_frontend"
};
private final String[] mGlobalSettings;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 2770833..de4ad20 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2212,6 +2212,7 @@
final IRemoteCallback callback = new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle data) throws RemoteException {
+ asyncTraceEnd("onUserSwitching-" + name, newUserId);
synchronized (mLock) {
long delayForObserver = SystemClock.elapsedRealtime()
- dispatchStartedTimeForObserver;
@@ -2229,8 +2230,6 @@
+ " ms after dispatchUserSwitch.");
}
- TimingsTraceAndSlog t2 = new TimingsTraceAndSlog(TAG);
- t2.traceBegin("onUserSwitchingReply-" + name);
curWaitingUserSwitchCallbacks.remove(name);
// Continue switching if all callbacks have been notified and
// user switching session is still valid
@@ -2239,13 +2238,11 @@
== mCurWaitingUserSwitchCallbacks)) {
sendContinueUserSwitchLU(uss, oldUserId, newUserId);
}
- t2.traceEnd();
}
}
};
- t.traceBegin("onUserSwitching-" + name);
+ asyncTraceBegin("onUserSwitching-" + name, newUserId);
mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(newUserId, callback);
- t.traceEnd();
} catch (RemoteException e) {
// Ignore
}
diff --git a/services/core/java/com/android/server/biometrics/Android.bp b/services/core/java/com/android/server/biometrics/Android.bp
new file mode 100644
index 0000000..6cbe4ad
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/Android.bp
@@ -0,0 +1,12 @@
+aconfig_declarations {
+ name: "biometrics_flags",
+ package: "com.android.server.biometrics",
+ srcs: [
+ "biometrics.aconfig",
+ ],
+}
+
+java_aconfig_library {
+ name: "biometrics_flags_lib",
+ aconfig_declarations: "biometrics_flags",
+}
diff --git a/services/core/java/com/android/server/biometrics/biometrics.aconfig b/services/core/java/com/android/server/biometrics/biometrics.aconfig
new file mode 100644
index 0000000..b537e0e
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/biometrics.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.biometrics"
+
+flag {
+ name: "face_vhal_feature"
+ namespace: "biometrics_framework"
+ description: "This flag controls tunscany virtual HAL feature"
+ bug: "294254230"
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 6f26e7b..5084b60 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -58,6 +58,7 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.SystemService;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -67,6 +68,8 @@
import com.android.server.biometrics.sensors.face.aidl.FaceProvider;
import com.android.server.biometrics.sensors.face.hidl.Face10;
+import com.google.android.collect.Lists;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -639,15 +642,24 @@
provider.second.scheduleGetFeature(provider.first, token, userId, feature,
new ClientMonitorCallbackConverter(receiver), opPackageName);
}
-
- private List<ServiceProvider> getAidlProviders() {
+ @NonNull
+ private List<ServiceProvider> getHidlProviders(
+ @NonNull List<FaceSensorPropertiesInternal> hidlSensors) {
final List<ServiceProvider> providers = new ArrayList<>();
- final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR);
- if (instances == null || instances.length == 0) {
- return providers;
+ for (FaceSensorPropertiesInternal hidlSensor : hidlSensors) {
+ providers.add(
+ Face10.newInstance(getContext(), mBiometricStateCallback,
+ hidlSensor, mLockoutResetDispatcher));
}
+ return providers;
+ }
+
+ @NonNull
+ private List<ServiceProvider> getAidlProviders(@NonNull List<String> instances) {
+ final List<ServiceProvider> providers = new ArrayList<>();
+
for (String instance : instances) {
final String fqName = IFace.DESCRIPTOR + "/" + instance;
final IFace face = IFace.Stub.asInterface(
@@ -676,17 +688,55 @@
super.registerAuthenticators_enforcePermission();
mRegistry.registerAll(() -> {
- final List<ServiceProvider> providers = new ArrayList<>();
- for (FaceSensorPropertiesInternal hidlSensor : hidlSensors) {
- providers.add(
- Face10.newInstance(getContext(), mBiometricStateCallback,
- hidlSensor, mLockoutResetDispatcher));
+ List<String> aidlSensors = new ArrayList<>();
+ final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR);
+ if (instances != null) {
+ aidlSensors.addAll(Lists.newArrayList(instances));
}
- providers.addAll(getAidlProviders());
+
+ final Pair<List<FaceSensorPropertiesInternal>, List<String>>
+ filteredInstances = filterAvailableHalInstances(hidlSensors, aidlSensors);
+
+ final List<ServiceProvider> providers = new ArrayList<>();
+ providers.addAll(getHidlProviders(filteredInstances.first));
+ providers.addAll(getAidlProviders(filteredInstances.second));
return providers;
});
}
+ private Pair<List<FaceSensorPropertiesInternal>, List<String>>
+ filterAvailableHalInstances(
+ @NonNull List<FaceSensorPropertiesInternal> hidlInstances,
+ @NonNull List<String> aidlInstances) {
+ if ((hidlInstances.size() + aidlInstances.size()) <= 1) {
+ return new Pair(hidlInstances, aidlInstances);
+ }
+
+ if (Flags.faceVhalFeature()) {
+ Slog.i(TAG, "Face VHAL feature is on");
+ } else {
+ Slog.i(TAG, "Face VHAL feature is off");
+ }
+
+ final int virtualAt = aidlInstances.indexOf("virtual");
+ if (Flags.faceVhalFeature() && Utils.isVirtualEnabled(getContext())) {
+ if (virtualAt != -1) {
+ //only virtual instance should be returned
+ return new Pair(new ArrayList<>(), List.of(aidlInstances.get(virtualAt)));
+ } else {
+ Slog.e(TAG, "Could not find virtual interface while it is enabled");
+ return new Pair(hidlInstances, aidlInstances);
+ }
+ } else {
+ //remove virtual instance
+ aidlInstances = new ArrayList<>(aidlInstances);
+ if (virtualAt != -1) {
+ aidlInstances.remove(virtualAt);
+ }
+ return new Pair(hidlInstances, aidlInstances);
+ }
+ }
+
@Override
public void addAuthenticatorsRegisteredCallback(
IFaceAuthenticatorsRegisteredCallback callback) {
@@ -749,7 +799,7 @@
void syncEnrollmentsNow() {
Utils.checkPermissionOrShell(getContext(), MANAGE_FACE);
- if (Utils.isVirtualEnabled(getContext())) {
+ if (Flags.faceVhalFeature() && Utils.isVirtualEnabled(getContext())) {
Slog.i(TAG, "Sync virtual enrollments");
final int userId = ActivityManager.getCurrentUser();
for (ServiceProvider provider : mRegistry.getProviders()) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index 51a9385..4502e5d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -128,7 +128,11 @@
vibrateSuccess();
try {
- getListener().onDetected(getSensorId(), getTargetUserId(), mIsStrongBiometric);
+ if (getListener() != null) {
+ getListener().onDetected(getSensorId(), getTargetUserId(), mIsStrongBiometric);
+ } else {
+ Slog.e(TAG, "Listener is null!");
+ }
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when sending onDetected", e);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index e072eeb..8736a53 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -3046,7 +3046,7 @@
public static void sendMessage(Message message) {
final SyncManager instance = getInstance();
- if (instance != null) {
+ if (instance != null && instance.mSyncHandler != null) {
instance.mSyncHandler.sendMessage(message);
}
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index d88fe8a..d2aff25 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -324,7 +324,8 @@
pw.println("mWhenToDream=" + mWhenToDream);
pw.println("mKeepDreamingWhenUnpluggingDefault=" + mKeepDreamingWhenUnpluggingDefault);
pw.println("getDozeComponent()=" + getDozeComponent());
- pw.println("mDreamOverlayServiceName=" + mDreamOverlayServiceName.flattenToString());
+ pw.println("mDreamOverlayServiceName="
+ + ComponentName.flattenToShortString(mDreamOverlayServiceName));
pw.println();
DumpUtils.dumpAsync(mHandler, (pw1, prefix) -> mController.dump(pw1), pw, "", 200);
diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
index 2ede56d..a2c8748 100644
--- a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
+++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
@@ -62,10 +62,10 @@
mWindowHandle.ownerUid = uid;
mWindowHandle.scaleFactor = 1.0f;
mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
- mWindowHandle.inputConfig =
- InputConfig.NOT_FOCUSABLE | InputConfig.SPY | InputConfig.TRUSTED_OVERLAY;
+ mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.SPY;
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
t.setInputWindowInfo(mInputSurface, mWindowHandle);
t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_GESTURE_MONITOR);
t.setPosition(mInputSurface, 0, 0);
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index 7726f40..dbbbed3 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -57,13 +57,13 @@
InputConfig.NOT_FOCUSABLE
| InputConfig.NOT_TOUCHABLE
| InputConfig.SPY
- | InputConfig.INTERCEPTS_STYLUS
- | InputConfig.TRUSTED_OVERLAY;
+ | InputConfig.INTERCEPTS_STYLUS;
// Configure the surface to receive stylus events across the entire display.
mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
t.setInputWindowInfo(mInputSurface, mWindowHandle);
t.setLayer(mInputSurface, InputManagerService.INPUT_OVERLAY_LAYER_HANDWRITING_SURFACE);
t.setPosition(mInputSurface, 0, 0);
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
index 26df162..749d6b0 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
@@ -224,6 +224,7 @@
@Nullable
HandwritingSession startHandwritingSession(
int requestId, int imePid, int imeUid, IBinder focusedWindowToken) {
+ clearPendingHandwritingDelegation();
if (mHandwritingSurface == null) {
Slog.e(TAG, "Cannot start handwriting session: Handwriting was not initialized.");
return null;
diff --git a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
index 2efb0be..b090334 100644
--- a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
+++ b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
@@ -259,19 +259,16 @@
.withZone(ZoneId.systemDefault());
pw.print(prefix);
- pw.println("ImeTrackerService#History.mLiveEntries: "
- + mLiveEntries.size() + " elements");
+ pw.println("mLiveEntries: " + mLiveEntries.size() + " elements");
for (final var entry: mLiveEntries.values()) {
- dumpEntry(entry, pw, prefix, formatter);
+ dumpEntry(entry, pw, prefix + " ", formatter);
}
-
pw.print(prefix);
- pw.println("ImeTrackerService#History.mEntries: "
- + mEntries.size() + " elements");
+ pw.println("mEntries: " + mEntries.size() + " elements");
for (final var entry: mEntries) {
- dumpEntry(entry, pw, prefix, formatter);
+ dumpEntry(entry, pw, prefix + " ", formatter);
}
}
@@ -279,22 +276,22 @@
private void dumpEntry(@NonNull Entry entry, @NonNull PrintWriter pw,
@NonNull String prefix, @NonNull DateTimeFormatter formatter) {
pw.print(prefix);
- pw.print(" #" + entry.mSequenceNumber);
+ pw.print("#" + entry.mSequenceNumber);
pw.print(" " + ImeTracker.Debug.typeToString(entry.mType));
pw.print(" - " + ImeTracker.Debug.statusToString(entry.mStatus));
pw.print(" - " + entry.mTag);
pw.println(" (" + entry.mDuration + "ms):");
pw.print(prefix);
- pw.print(" startTime=" + formatter.format(Instant.ofEpochMilli(entry.mStartTime)));
+ pw.print(" startTime=" + formatter.format(Instant.ofEpochMilli(entry.mStartTime)));
pw.println(" " + ImeTracker.Debug.originToString(entry.mOrigin));
pw.print(prefix);
- pw.print(" reason=" + InputMethodDebug.softInputDisplayReasonToString(entry.mReason));
+ pw.print(" reason=" + InputMethodDebug.softInputDisplayReasonToString(entry.mReason));
pw.println(" " + ImeTracker.Debug.phaseToString(entry.mPhase));
pw.print(prefix);
- pw.println(" requestWindowName=" + entry.mRequestWindowName);
+ pw.println(" requestWindowName=" + entry.mRequestWindowName);
}
/** A history entry. */
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
index 2e0274b..0dd48ae 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -588,12 +588,12 @@
proto.write(INPUT_SHOWN, mInputShown);
}
- void dump(PrintWriter pw) {
+ void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
final Printer p = new PrintWriterPrinter(pw);
- p.println(" mRequestedShowExplicitly=" + mRequestedShowExplicitly
+ p.println(prefix + "mRequestedShowExplicitly=" + mRequestedShowExplicitly
+ " mShowForced=" + mShowForced);
- p.println(" mImeHiddenByDisplayPolicy=" + mPolicy.isImeHiddenByDisplayPolicy());
- p.println(" mInputShown=" + mInputShown);
+ p.println(prefix + "mImeHiddenByDisplayPolicy=" + mPolicy.isImeHiddenByDisplayPolicy());
+ p.println(prefix + "mInputShown=" + mInputShown);
}
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index e58f272..699e9c8 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -358,12 +358,12 @@
@Override
public String toString() {
- return "SessionState{uid " + mClient.mUid + " pid " + mClient.mPid
- + " method " + Integer.toHexString(
+ return "SessionState{uid=" + mClient.mUid + " pid=" + mClient.mPid
+ + " method=" + Integer.toHexString(
IInputMethodInvoker.getBinderIdentityHashCode(mMethod))
- + " session " + Integer.toHexString(
+ + " session=" + Integer.toHexString(
System.identityHashCode(mSession))
- + " channel " + mChannel
+ + " channel=" + mChannel
+ "}";
}
@@ -388,9 +388,9 @@
@Override
public String toString() {
- return "AccessibilitySessionState{uid " + mClient.mUid + " pid " + mClient.mPid
- + " id " + Integer.toHexString(mId)
- + " session " + Integer.toHexString(
+ return "AccessibilitySessionState{uid=" + mClient.mUid + " pid=" + mClient.mPid
+ + " id=" + Integer.toHexString(mId)
+ + " session=" + Integer.toHexString(
System.identityHashCode(mSession))
+ "}";
}
@@ -884,47 +884,47 @@
continue;
}
pw.print(prefix);
- pw.println("SoftInputShowHideHistory #" + entry.mSequenceNumber + ":");
+ pw.println("SoftInputShowHide #" + entry.mSequenceNumber + ":");
pw.print(prefix);
- pw.println(" time=" + formatter.format(Instant.ofEpochMilli(entry.mWallTime))
+ pw.println(" time=" + formatter.format(Instant.ofEpochMilli(entry.mWallTime))
+ " (timestamp=" + entry.mTimestamp + ")");
pw.print(prefix);
- pw.print(" reason=" + InputMethodDebug.softInputDisplayReasonToString(
+ pw.print(" reason=" + InputMethodDebug.softInputDisplayReasonToString(
entry.mReason));
pw.println(" inFullscreenMode=" + entry.mInFullscreenMode);
pw.print(prefix);
- pw.println(" requestClient=" + entry.mClientState);
+ pw.println(" requestClient=" + entry.mClientState);
pw.print(prefix);
- pw.println(" focusedWindowName=" + entry.mFocusedWindowName);
+ pw.println(" focusedWindowName=" + entry.mFocusedWindowName);
pw.print(prefix);
- pw.println(" requestWindowName=" + entry.mRequestWindowName);
+ pw.println(" requestWindowName=" + entry.mRequestWindowName);
pw.print(prefix);
- pw.println(" imeControlTargetName=" + entry.mImeControlTargetName);
+ pw.println(" imeControlTargetName=" + entry.mImeControlTargetName);
pw.print(prefix);
- pw.println(" imeTargetNameFromWm=" + entry.mImeTargetNameFromWm);
+ pw.println(" imeTargetNameFromWm=" + entry.mImeTargetNameFromWm);
pw.print(prefix);
- pw.println(" imeSurfaceParentName=" + entry.mImeSurfaceParentName);
+ pw.println(" imeSurfaceParentName=" + entry.mImeSurfaceParentName);
pw.print(prefix);
- pw.print(" editorInfo: ");
+ pw.print(" editorInfo:");
if (entry.mEditorInfo != null) {
pw.print(" inputType=" + entry.mEditorInfo.inputType);
pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions);
pw.println(" fieldId (viewId)=" + entry.mEditorInfo.fieldId);
} else {
- pw.println("null");
+ pw.println(" null");
}
pw.print(prefix);
- pw.println(" focusedWindowSoftInputMode=" + InputMethodDebug.softInputModeToString(
+ pw.println(" focusedWindowSoftInputMode=" + InputMethodDebug.softInputModeToString(
entry.mFocusedWindowSoftInputMode));
}
}
@@ -1052,30 +1052,30 @@
pw.println("StartInput #" + entry.mSequenceNumber + ":");
pw.print(prefix);
- pw.println(" time=" + formatter.format(Instant.ofEpochMilli(entry.mWallTime))
+ pw.println(" time=" + formatter.format(Instant.ofEpochMilli(entry.mWallTime))
+ " (timestamp=" + entry.mTimestamp + ")"
+ " reason="
+ InputMethodDebug.startInputReasonToString(entry.mStartInputReason)
+ " restarting=" + entry.mRestarting);
pw.print(prefix);
- pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
+ pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
pw.print(" imeUserId=" + entry.mImeUserId);
pw.println(" imeDisplayId=" + entry.mImeDisplayId);
pw.print(prefix);
- pw.println(" targetWin=" + entry.mTargetWindowString
+ pw.println(" targetWin=" + entry.mTargetWindowString
+ " [" + entry.mEditorInfo.packageName + "]"
+ " targetUserId=" + entry.mTargetUserId
+ " targetDisplayId=" + entry.mTargetDisplayId
+ " clientBindSeq=" + entry.mClientBindSequenceNumber);
pw.print(prefix);
- pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString(
+ pw.println(" softInputMode=" + InputMethodDebug.softInputModeToString(
entry.mTargetWindowSoftInputMode));
pw.print(prefix);
- pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType)
+ pw.println(" inputType=0x" + Integer.toHexString(entry.mEditorInfo.inputType)
+ " imeOptions=0x" + Integer.toHexString(entry.mEditorInfo.imeOptions)
+ " fieldId=0x" + Integer.toHexString(entry.mEditorInfo.fieldId)
+ " fieldName=" + entry.mEditorInfo.fieldName
@@ -3369,13 +3369,19 @@
@BinderThread
@Override
public void startStylusHandwriting(IInputMethodClient client) {
+ startStylusHandwriting(client, false /* usesDelegation */);
+ }
+
+ private void startStylusHandwriting(IInputMethodClient client, boolean usesDelegation) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.startStylusHandwriting");
try {
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#startStylusHandwriting");
int uid = Binder.getCallingUid();
synchronized (ImfLock.class) {
- mHwController.clearPendingHandwritingDelegation();
+ if (!usesDelegation) {
+ mHwController.clearPendingHandwritingDelegation();
+ }
if (!canInteractWithImeLocked(uid, client, "startStylusHandwriting",
null /* statsToken */)) {
return;
@@ -3457,7 +3463,7 @@
return false;
}
- startStylusHandwriting(client);
+ startStylusHandwriting(client, true /* usesDelegation */);
return true;
}
@@ -5946,11 +5952,11 @@
p.println(" InputMethod #" + i + ":");
info.dump(p, " ");
}
- p.println(" Clients:");
+ p.println(" ClientStates:");
final int numClients = mClients.size();
for (int i = 0; i < numClients; ++i) {
final ClientState ci = mClients.valueAt(i);
- p.println(" Client " + ci + ":");
+ p.println(" " + ci + ":");
p.println(" client=" + ci.mClient);
p.println(" fallbackInputConnection=" + ci.mFallbackInputConnection);
p.println(" sessionRequested=" + ci.mSessionRequested);
@@ -5977,7 +5983,7 @@
method = getCurMethodLocked();
p.println(" mCurMethod=" + getCurMethodLocked());
p.println(" mEnabledSession=" + mEnabledSession);
- mVisibilityStateComputer.dump(pw);
+ mVisibilityStateComputer.dump(pw, " ");
p.println(" mInFullscreenMode=" + mInFullscreenMode);
p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
p.println(" ENABLE_HIDE_IME_CAPTION_BAR="
@@ -5991,13 +5997,13 @@
mSettings.dumpLocked(p, " ");
p.println(" mStartInputHistory:");
- mStartInputHistory.dump(pw, " ");
+ mStartInputHistory.dump(pw, " ");
p.println(" mSoftInputShowHideHistory:");
- mSoftInputShowHideHistory.dump(pw, " ");
+ mSoftInputShowHideHistory.dump(pw, " ");
p.println(" mImeTrackerService#History:");
- mImeTrackerService.dump(pw, " ");
+ mImeTrackerService.dump(pw, " ");
}
// Exit here for critical dump, as remaining sections require IPCs to other processes.
diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
index 4873467..7cf6eae 100644
--- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
+++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
@@ -154,6 +154,23 @@
}
/**
+ * Returns whether the given uid corresponds to the last process to audio or not.
+ *
+ * <p> This is useful for handling the cases where the foreground app is playing media without
+ * a media session. Then, volume events should affect the local music stream rather than other
+ * media sessions.
+ *
+ * @return {@code true} if the given uid corresponds to the last process to audio or
+ * {@code false} otherwise.
+ */
+ public boolean hasUidPlayedAudioLast(int uid) {
+ synchronized (mLock) {
+ return !mSortedAudioPlaybackClientUids.isEmpty()
+ && uid == mSortedAudioPlaybackClientUids.get(0);
+ }
+ }
+
+ /**
* Returns if the audio playback is active for the uid.
*/
public boolean isPlaybackActive(int uid) {
@@ -234,7 +251,7 @@
}
}
- // Update mSortedAuioPlaybackClientUids.
+ // Update mSortedAudioPlaybackClientUids.
for (int i = 0; i < activeAudioPlaybackConfigs.size(); ++i) {
AudioPlaybackConfiguration config = activeAudioPlaybackConfigs.valueAt(i);
final int uid = config.getClientUid();
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index e538355..4892c22 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -2100,34 +2100,36 @@
if (!hasAddedOrModifiedRoutes && !hasRemovedRoutes) {
return;
}
- List<RouterRecord> routerRecordsWithModifyAudioRoutingPermission =
- getRouterRecords(true);
- List<RouterRecord> routerRecordsWithoutModifyAudioRoutingPermission =
- getRouterRecords(false);
+ List<RouterRecord> routerRecordsWithSystemRoutingPermission =
+ getRouterRecords(/* hasSystemRoutingPermission= */ true);
+ List<RouterRecord> routerRecordsWithoutSystemRoutingPermission =
+ getRouterRecords(/* hasSystemRoutingPermission= */ false);
List<IMediaRouter2Manager> managers = getManagers();
// Managers receive all provider updates with all routes.
notifyRoutesUpdatedToManagers(
managers, new ArrayList<>(mLastNotifiedRoutesToPrivilegedRouters.values()));
- // Routers with modify audio permission (usually system routers) receive all provider
- // updates with all routes.
+ // Routers with system routing access (either via {@link MODIFY_AUDIO_ROUTING} or
+ // {@link BLUETOOTH_CONNECT} + {@link BLUETOOTH_SCAN}) receive all provider updates
+ // with all routes.
notifyRoutesUpdatedToRouterRecords(
- routerRecordsWithModifyAudioRoutingPermission,
+ routerRecordsWithSystemRoutingPermission,
new ArrayList<>(mLastNotifiedRoutesToPrivilegedRouters.values()));
if (!isSystemProvider) {
// Regular routers receive updates from all non-system providers with all non-system
// routes.
notifyRoutesUpdatedToRouterRecords(
- routerRecordsWithoutModifyAudioRoutingPermission,
+ routerRecordsWithoutSystemRoutingPermission,
new ArrayList<>(mLastNotifiedRoutesToNonPrivilegedRouters.values()));
} else if (hasAddedOrModifiedRoutes) {
- // On system provider updates, regular routers receive the updated default route.
- // This is the only system route they should receive.
+ // On system provider updates, routers without system routing access
+ // receive the updated default route. This is the only system route they should
+ // receive.
mLastNotifiedRoutesToNonPrivilegedRouters.put(defaultRoute.getId(), defaultRoute);
notifyRoutesUpdatedToRouterRecords(
- routerRecordsWithoutModifyAudioRoutingPermission,
+ routerRecordsWithoutSystemRoutingPermission,
new ArrayList<>(mLastNotifiedRoutesToNonPrivilegedRouters.values()));
}
}
@@ -2533,7 +2535,7 @@
}
}
- private List<RouterRecord> getRouterRecords(boolean hasModifyAudioRoutingPermission) {
+ private List<RouterRecord> getRouterRecords(boolean hasSystemRoutingPermission) {
MediaRouter2ServiceImpl service = mServiceRef.get();
List<RouterRecord> routerRecords = new ArrayList<>();
if (service == null) {
@@ -2541,7 +2543,7 @@
}
synchronized (service.mLock) {
for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
- if (hasModifyAudioRoutingPermission
+ if (hasSystemRoutingPermission
== routerRecord.hasSystemRoutingPermission()) {
routerRecords.add(routerRecord);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index f4c9518..803ab28 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -19,7 +19,6 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.os.UserHandle.ALL;
import static android.os.UserHandle.CURRENT;
-
import static com.android.server.media.MediaKeyDispatcher.KEY_EVENT_LONG_PRESS;
import static com.android.server.media.MediaKeyDispatcher.isDoubleTapOverridden;
import static com.android.server.media.MediaKeyDispatcher.isLongPressOverridden;
@@ -85,6 +84,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.media.flags.Flags;
import com.android.server.LocalManagerRegistry;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -2192,6 +2192,21 @@
isValidLocalStreamType(suggestedStream)
&& AudioSystem.isStreamActive(suggestedStream, 0);
+ if (session != null && session.getUid() != uid
+ && mAudioPlayerStateMonitor.hasUidPlayedAudioLast(uid)) {
+ if (Flags.adjustVolumeForForegroundAppPlayingAudioWithoutMediaSession()) {
+ // The app in the foreground has been the last app to play media locally.
+ // Therefore, We ignore the chosen session so that volume events affect the
+ // local music stream instead. See b/275185436 for details.
+ Log.d(TAG, "Ignoring session=" + session + " and adjusting suggestedStream="
+ + suggestedStream + " instead");
+ session = null;
+ } else {
+ Log.d(TAG, "Session=" + session + " will not be not ignored and will receive"
+ + " the volume adjustment event");
+ }
+ }
+
if (session == null || preferSuggestedStream) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Adjusting suggestedStream=" + suggestedStream + " by " + direction
diff --git a/services/core/java/com/android/server/notification/OWNERS b/services/core/java/com/android/server/notification/OWNERS
index 6c4dd6d..72c4529 100644
--- a/services/core/java/com/android/server/notification/OWNERS
+++ b/services/core/java/com/android/server/notification/OWNERS
@@ -1,4 +1,4 @@
-# Bug component: 34005
+# Bug component: 1305560
juliacr@google.com
yurilin@google.com
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 74d3417..4c9ec9d 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1020,7 +1020,7 @@
try {
final ClientTransaction transaction = ClientTransaction.obtain(
r.app.getThread(), r.token);
- transaction.addCallback(EnterPipRequestedItem.obtain());
+ transaction.addCallback(EnterPipRequestedItem.obtain(r.token));
mService.getLifecycleManager().scheduleTransaction(transaction);
return true;
} catch (Exception e) {
@@ -1042,7 +1042,7 @@
try {
final ClientTransaction transaction = ClientTransaction.obtain(
r.app.getThread(), r.token);
- transaction.addCallback(PipStateTransactionItem.obtain(pipState));
+ transaction.addCallback(PipStateTransactionItem.obtain(r.token, pipState));
mService.getLifecycleManager().scheduleTransaction(transaction);
} catch (Exception e) {
Slog.w(TAG, "Failed to send pip state transaction item: "
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b2eb383..dca2b6f 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1443,7 +1443,7 @@
config);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
- MoveToDisplayItem.obtain(displayId, config));
+ MoveToDisplayItem.obtain(token, displayId, config));
} catch (RemoteException e) {
// If process died, whatever.
}
@@ -1460,7 +1460,7 @@
+ "config: %s", this, config);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
- ActivityConfigurationChangeItem.obtain(config));
+ ActivityConfigurationChangeItem.obtain(token, config));
} catch (RemoteException e) {
// If process died, whatever.
}
@@ -1481,7 +1481,7 @@
this, onTop);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
- TopResumedActivityChangeItem.obtain(onTop));
+ TopResumedActivityChangeItem.obtain(token, onTop));
} catch (RemoteException e) {
// If process died, whatever.
Slog.w(TAG, "Failed to send top-resumed=" + onTop + " to " + this, e);
@@ -2728,7 +2728,7 @@
try {
mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_ATTACH_TO_CLIENT;
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
- TransferSplashScreenViewStateItem.obtain(parcelable,
+ TransferSplashScreenViewStateItem.obtain(token, parcelable,
windowAnimationLeash));
scheduleTransferSplashScreenTimeout();
} catch (Exception e) {
@@ -3895,7 +3895,7 @@
try {
if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + this);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
- DestroyActivityItem.obtain(finishing, configChangeFlags));
+ DestroyActivityItem.obtain(token, finishing, configChangeFlags));
} catch (Exception e) {
// We can just ignore exceptions here... if the process has crashed, our death
// notification will clean things up.
@@ -4803,7 +4803,7 @@
final ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
list.add(new ResultInfo(resultWho, requestCode, resultCode, data));
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
- ActivityResultItem.obtain(list));
+ ActivityResultItem.obtain(token, list));
return;
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending result to " + this, e);
@@ -4816,7 +4816,7 @@
final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), token);
// Build result to be returned immediately.
transaction.addCallback(ActivityResultItem.obtain(
- List.of(new ResultInfo(resultWho, requestCode, resultCode, data))));
+ token, List.of(new ResultInfo(resultWho, requestCode, resultCode, data))));
// When the activity result is delivered, the activity will transition to RESUMED.
// Since the activity is only resumed so the result can be immediately delivered,
// return it to its original lifecycle state.
@@ -4857,13 +4857,13 @@
private ActivityLifecycleItem getLifecycleItemForCurrentStateForResult() {
switch (mState) {
case STARTED:
- return StartActivityItem.obtain(null);
+ return StartActivityItem.obtain(token, null);
case PAUSING:
case PAUSED:
- return PauseActivityItem.obtain();
+ return PauseActivityItem.obtain(token);
case STOPPING:
case STOPPED:
- return StopActivityItem.obtain(configChangeFlags);
+ return StopActivityItem.obtain(token, configChangeFlags);
default:
// Do not send a result immediately if the activity is in state INITIALIZING,
// RESTARTING_PROCESS, FINISHING, DESTROYING, or DESTROYED.
@@ -4909,7 +4909,7 @@
// so only if activity is currently RESUMED. Otherwise, client may have extra
// life-cycle calls to RESUMED (and PAUSED later).
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
- NewIntentItem.obtain(ar, mState == RESUMED));
+ NewIntentItem.obtain(token, ar, mState == RESUMED));
unsent = false;
} catch (RemoteException e) {
Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
@@ -6144,7 +6144,7 @@
shortComponentName, "userLeaving=false", "make-active");
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
- PauseActivityItem.obtain(finishing, false /* userLeaving */,
+ PauseActivityItem.obtain(token, finishing, false /* userLeaving */,
configChangeFlags, false /* dontReport */, mAutoEnteringPip));
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e);
@@ -6157,7 +6157,7 @@
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
- StartActivityItem.obtain(takeOptions()));
+ StartActivityItem.obtain(token, takeOptions()));
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e);
}
@@ -6455,7 +6455,7 @@
EventLogTags.writeWmStopActivity(
mUserId, System.identityHashCode(this), shortComponentName);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
- StopActivityItem.obtain(configChangeFlags));
+ StopActivityItem.obtain(token, configChangeFlags));
mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT);
} catch (Exception e) {
@@ -9870,17 +9870,17 @@
(andResume ? "RESUMED" : "PAUSED"), this, Debug.getCallers(6));
forceNewConfig = false;
startRelaunching();
- final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults,
- pendingNewIntents, configChangeFlags,
+ final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(token,
+ pendingResults, pendingNewIntents, configChangeFlags,
new MergedConfiguration(getProcessGlobalConfiguration(),
getMergedOverrideConfiguration()),
preserveWindow);
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
- lifecycleItem = ResumeActivityItem.obtain(isTransitionForward(),
+ lifecycleItem = ResumeActivityItem.obtain(token, isTransitionForward(),
shouldSendCompatFakeFocus());
} else {
- lifecycleItem = PauseActivityItem.obtain();
+ lifecycleItem = PauseActivityItem.obtain(token);
}
final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), token);
transaction.addCallback(callbackItem);
@@ -9977,7 +9977,7 @@
// {@link ActivityTaskManagerService.activityStopped}).
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
- StopActivityItem.obtain(0 /* configChanges */));
+ StopActivityItem.obtain(token, 0 /* configChanges */));
} catch (RemoteException e) {
Slog.w(TAG, "Exception thrown during restart " + this, e);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 69e679d..e523119 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -929,8 +929,8 @@
final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
final int deviceId = getDeviceIdForDisplayId(r.getDisplayId());
- clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
- System.identityHashCode(r), r.info,
+ clientTransaction.addCallback(LaunchActivityItem.obtain(r.token,
+ new Intent(r.intent), System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
@@ -944,10 +944,10 @@
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
- lifecycleItem = ResumeActivityItem.obtain(isTransitionForward,
+ lifecycleItem = ResumeActivityItem.obtain(r.token, isTransitionForward,
r.shouldSendCompatFakeFocus());
} else {
- lifecycleItem = PauseActivityItem.obtain();
+ lifecycleItem = PauseActivityItem.obtain(r.token);
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index f96f99d..c4ed0dd 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -228,9 +228,9 @@
+ "activityRecord=%s", activity);
final ClientTransaction transaction = ClientTransaction.obtain(
activity.app.getThread(), activity.token);
- transaction.addCallback(
- RefreshCallbackItem.obtain(cycleThroughStop ? ON_STOP : ON_PAUSE));
- transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(
+ transaction.addCallback(RefreshCallbackItem.obtain(activity.token,
+ cycleThroughStop ? ON_STOP : ON_PAUSE));
+ transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(activity.token,
/* isForward */ false, /* shouldSendCompatFakeFocus */ false));
activity.mAtmService.getLifecycleManager().scheduleTransaction(transaction);
mHandler.postDelayed(
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 0f1a105..8519e4d 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -21,7 +21,6 @@
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
-
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.wm.DragDropController.MSG_ANIMATION_END;
@@ -33,7 +32,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.MY_PID;
import static com.android.server.wm.WindowManagerService.MY_UID;
-
import static java.util.concurrent.CompletableFuture.completedFuture;
import android.animation.Animator;
@@ -48,7 +46,6 @@
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
-import android.os.InputConfig;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -186,8 +183,13 @@
// Crop the input surface to the display size.
mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
+ // Make trusted overlay to not block any touches while D&D ongoing and allowing
+ // touches to pass through to windows underneath. This allows user to interact with the
+ // UI to navigate while dragging.
+ h.setTrustedOverlay(mTransaction, mInputSurface, true);
mTransaction.show(mInputSurface)
.setInputWindowInfo(mInputSurface, h)
+ .setTrustedOverlay(mInputSurface, true)
.setLayer(mInputSurface, Integer.MAX_VALUE)
.setCrop(mInputSurface, mTmpClipRect);
@@ -377,11 +379,6 @@
mDragWindowHandle.ownerUid = MY_UID;
mDragWindowHandle.scaleFactor = 1.0f;
- // InputConfig.TRUSTED_OVERLAY: To not block any touches while D&D ongoing and allowing
- // touches to pass through to windows underneath. This allows user to interact with the
- // UI to navigate while dragging.
- mDragWindowHandle.inputConfig = InputConfig.TRUSTED_OVERLAY;
-
// The drag window cannot receive new touches.
mDragWindowHandle.touchableRegion.setEmpty();
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 39622c1..c21930d 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -74,7 +74,7 @@
mWindowHandle.ownerPid = WindowManagerService.MY_PID;
mWindowHandle.ownerUid = WindowManagerService.MY_UID;
mWindowHandle.scaleFactor = 1.0f;
- mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE | InputConfig.TRUSTED_OVERLAY;
+ mWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE;
mInputSurface = mService.makeSurfaceBuilder(
mService.mRoot.getDisplayContent(displayId).getSession())
@@ -129,12 +129,14 @@
void show(SurfaceControl.Transaction t, WindowContainer w) {
t.show(mInputSurface);
+ mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
t.setInputWindowInfo(mInputSurface, mWindowHandle);
t.setRelativeLayer(mInputSurface, w.getSurfaceControl(), 1);
}
void show(SurfaceControl.Transaction t, int layer) {
t.show(mInputSurface);
+ mWindowHandle.setTrustedOverlay(t, mInputSurface, true);
t.setInputWindowInfo(mInputSurface, mWindowHandle);
t.setLayer(mInputSurface, layer);
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 825d38b..f77da62 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -40,12 +40,10 @@
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.LOGTAG_INPUT_FOCUS;
-
import static java.lang.Integer.MAX_VALUE;
import android.annotation.Nullable;
@@ -732,7 +730,7 @@
new InputWindowHandle(null /* inputApplicationHandle */, displayId));
inputWindowHandle.setName(name);
inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY);
- inputWindowHandle.setTrustedOverlay(true);
+ inputWindowHandle.setTrustedOverlay(t, sc, true);
populateOverlayInputInfo(inputWindowHandle);
setInputWindowInfoIfNeeded(t, sc, inputWindowHandle);
}
diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
index 64b7a60..90d81bd 100644
--- a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
+++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
@@ -195,6 +195,11 @@
mChanged = true;
}
+ void setTrustedOverlay(SurfaceControl.Transaction t, SurfaceControl sc,
+ boolean trustedOverlay) {
+ mHandle.setTrustedOverlay(t, sc, trustedOverlay);
+ }
+
void setOwnerPid(int pid) {
if (mHandle.ownerPid == pid) {
return;
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index 45cf10b..579fd14 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -29,6 +29,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.FeatureFlags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -90,13 +91,6 @@
"enable_app_compat_user_aspect_ratio_fullscreen";
private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN = true;
- // Whether the letterbox wallpaper style is enabled by default
- private static final String KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER =
- "enable_letterbox_background_wallpaper";
-
- // TODO(b/290048978): Enable wallpaper as default letterbox background.
- private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER = false;
-
/**
* Override of aspect ratio for fixed orientation letterboxing that is set via ADB with
* set-fixed-orientation-letterbox-aspect-ratio or via {@link
@@ -185,6 +179,9 @@
@NonNull
private final LetterboxConfigurationPersister mLetterboxConfigurationPersister;
+ @NonNull
+ private final FeatureFlags mFeatureFlags;
+
// Aspect ratio of letterbox for fixed orientation, values <=
// MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO will be ignored.
private float mFixedOrientationLetterboxAspectRatio;
@@ -301,7 +298,8 @@
// Flags dynamically updated with {@link android.provider.DeviceConfig}.
@NonNull private final SynchedDeviceConfig mDeviceConfig;
- LetterboxConfiguration(@NonNull final Context systemUiContext) {
+ LetterboxConfiguration(@NonNull final Context systemUiContext,
+ @NonNull FeatureFlags featureFags) {
this(systemUiContext, new LetterboxConfigurationPersister(
() -> readLetterboxHorizontalReachabilityPositionFromConfig(
systemUiContext, /* forBookMode */ false),
@@ -310,14 +308,16 @@
() -> readLetterboxHorizontalReachabilityPositionFromConfig(
systemUiContext, /* forBookMode */ true),
() -> readLetterboxVerticalReachabilityPositionFromConfig(
- systemUiContext, /* forTabletopMode */ true)));
+ systemUiContext, /* forTabletopMode */ true)),
+ featureFags);
}
@VisibleForTesting
LetterboxConfiguration(@NonNull final Context systemUiContext,
- @NonNull final LetterboxConfigurationPersister letterboxConfigurationPersister) {
+ @NonNull final LetterboxConfigurationPersister letterboxConfigurationPersister,
+ @NonNull FeatureFlags featureFags) {
mContext = systemUiContext;
-
+ mFeatureFlags = featureFags;
mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
R.dimen.config_fixedOrientationLetterboxAspectRatio);
mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext);
@@ -385,8 +385,6 @@
DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS,
mContext.getResources().getBoolean(
R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled))
- .addDeviceConfigEntry(KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER,
- DEFAULT_VALUE_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER, /* enabled */ true)
.addDeviceConfigEntry(KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN,
DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN,
mContext.getResources().getBoolean(
@@ -544,8 +542,7 @@
}
/**
- * Resets letterbox background type value depending on the
- * {@link #KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER} built time and runtime flags.
+ * Resets letterbox background type value depending on the built time and runtime flags.
*
* <p>If enabled, the letterbox background type value is set toZ
* {@link #LETTERBOX_BACKGROUND_WALLPAPER}. When disabled the letterbox background type value
@@ -555,12 +552,11 @@
mLetterboxBackgroundTypeOverride = LETTERBOX_BACKGROUND_OVERRIDE_UNSET;
}
- // Returns KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER if the DeviceConfig flag is enabled
- // or the value in com.android.internal.R.integer.config_letterboxBackgroundType if the flag
- // is disabled.
+ // Returns LETTERBOX_BACKGROUND_WALLPAPER if the flag is enabled or the value in
+ // com.android.internal.R.integer.config_letterboxBackgroundType if the flag is disabled.
@LetterboxBackgroundType
private int getDefaultLetterboxBackgroundType() {
- return mDeviceConfig.getFlagValue(KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER)
+ return mFeatureFlags.letterboxBackgroundWallpaperFlag()
? LETTERBOX_BACKGROUND_WALLPAPER : mLetterboxBackgroundType;
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 184de58..f33ecaa 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -301,12 +301,9 @@
}
// Always update the reordering time when this is called to ensure that the timeout
- // is reset. Extend this duration when running in tests.
- final long timeout = ActivityManager.isRunningInUserTestHarness()
- ? mFreezeTaskListTimeoutMs * 10
- : mFreezeTaskListTimeoutMs;
+ // is reset
mService.mH.removeCallbacks(mResetFreezeTaskListOnTimeoutRunnable);
- mService.mH.postDelayed(mResetFreezeTaskListOnTimeoutRunnable, timeout);
+ mService.mH.postDelayed(mResetFreezeTaskListOnTimeoutRunnable, mFreezeTaskListTimeoutMs);
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 6dc896a..57f44cb 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1466,13 +1466,13 @@
if (DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a);
}
- transaction.addCallback(ActivityResultItem.obtain(a));
+ transaction.addCallback(ActivityResultItem.obtain(next.token, a));
}
}
if (next.newIntents != null) {
transaction.addCallback(
- NewIntentItem.obtain(next.newIntents, true /* resume */));
+ NewIntentItem.obtain(next.token, next.newIntents, true /* resume */));
}
// Well the app will no longer be stopped.
@@ -1486,7 +1486,7 @@
next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
next.abortAndClearOptionsAnimation();
transaction.setLifecycleStateRequest(
- ResumeActivityItem.obtain(next.app.getReportedProcState(),
+ ResumeActivityItem.obtain(next.token, next.app.getReportedProcState(),
dc.isNextTransitionForward(), next.shouldSendCompatFakeFocus()));
mAtmService.getLifecycleManager().scheduleTransaction(transaction);
@@ -1726,7 +1726,7 @@
prev.shortComponentName, "userLeaving=" + userLeaving, reason);
mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
- prev.token, PauseActivityItem.obtain(prev.finishing, userLeaving,
+ prev.token, PauseActivityItem.obtain(prev.token, prev.finishing, userLeaving,
prev.configChangeFlags, pauseImmediately, autoEnteringPip));
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index e4b9571..0d78701 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -1147,7 +1147,7 @@
Transition.asyncTraceBegin("animating", 0x41bfaf1 /* hashcode of TAG */);
} else if (!animatingState && mAnimatingState) {
t.setEarlyWakeupEnd();
- mAtm.mWindowManager.requestTraversal();
+ mAtm.mWindowManager.scheduleAnimationLocked();
mSnapshotController.setPause(false);
mAnimatingState = false;
Transition.asyncTraceEnd(0x41bfaf1 /* hashcode of TAG */);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 439b719..e720446 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -97,7 +97,6 @@
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN;
import static android.window.WindowProviderService.isWindowProviderService;
-
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT;
@@ -334,6 +333,7 @@
import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
import com.android.server.power.ShutdownThread;
import com.android.server.utils.PriorityDump;
+import com.android.window.flags.FeatureFlagsImpl;
import dalvik.annotation.optimization.NeverCompile;
@@ -1175,7 +1175,8 @@
mLetterboxConfiguration = new LetterboxConfiguration(
// Using SysUI context to have access to Material colors extracted from Wallpaper.
- ActivityThread.currentActivityThread().getSystemUiContext());
+ ActivityThread.currentActivityThread().getSystemUiContext(),
+ new FeatureFlagsImpl());
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
@@ -8868,11 +8869,6 @@
h.inputConfig |= InputConfig.NOT_FOCUSABLE;
}
- // Check private trusted overlay flag to set trustedOverlay field of input window handle.
- if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
- h.inputConfig |= InputConfig.TRUSTED_OVERLAY;
- }
-
h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
h.ownerUid = callingUid;
h.ownerPid = callingPid;
@@ -8892,6 +8888,8 @@
}
final SurfaceControl.Transaction t = mTransactionFactory.get();
+ // Check private trusted overlay flag to set trustedOverlay field of input window handle.
+ h.setTrustedOverlay(t, surface, (privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0);
t.setInputWindowInfo(surface, h);
t.apply();
t.close();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b12cc0b..822082b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -28,6 +28,7 @@
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.PowerManager.DRAW_WAKE_LOCK;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.view.InputWindowHandle.USE_SURFACE_TRUSTED_OVERLAY;
import static android.view.SurfaceControl.Transaction;
import static android.view.SurfaceControl.getGlobalTransaction;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
@@ -98,7 +99,6 @@
import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
-
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -1112,7 +1112,9 @@
mInputWindowHandle.setName(getName());
mInputWindowHandle.setPackageName(mAttrs.packageName);
mInputWindowHandle.setLayoutParamsType(mAttrs.type);
- mInputWindowHandle.setTrustedOverlay(shouldWindowHandleBeTrusted(s));
+ if (!USE_SURFACE_TRUSTED_OVERLAY) {
+ mInputWindowHandle.setTrustedOverlay(isWindowTrustedOverlay());
+ }
if (DEBUG) {
Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -1193,12 +1195,12 @@
: service.mAtmService.getProcessController(s.mPid, s.mUid);
}
- boolean shouldWindowHandleBeTrusted(Session s) {
+ private boolean isWindowTrustedOverlay() {
return InputMonitor.isTrustedOverlay(mAttrs.type)
|| ((mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
- && s.mCanAddInternalSystemWindow)
+ && mSession.mCanAddInternalSystemWindow)
|| ((mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY) != 0
- && s.mCanCreateSystemApplicationOverlay);
+ && mSession.mCanCreateSystemApplicationOverlay);
}
int getTouchOcclusionMode() {
@@ -5192,6 +5194,9 @@
updateFrameRateSelectionPriorityIfNeeded();
updateScaleIfNeeded();
mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
+ if (USE_SURFACE_TRUSTED_OVERLAY) {
+ getSyncTransaction().setTrustedOverlay(mSurfaceControl, isWindowTrustedOverlay());
+ }
}
super.prepareSurfaces();
}
@@ -5944,7 +5949,13 @@
}
boolean isTrustedOverlay() {
- return mInputWindowHandle.isTrustedOverlay();
+ if (USE_SURFACE_TRUSTED_OVERLAY) {
+ WindowState parentWindow = getParentWindow();
+ return isWindowTrustedOverlay() || (parentWindow != null
+ && parentWindow.isWindowTrustedOverlay());
+ } else {
+ return mInputWindowHandle.isTrustedOverlay();
+ }
}
public boolean receiveFocusFromTapOutside() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index f2ab827..21b1291 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -624,7 +624,7 @@
}
/**
- * Retrieves the global policy set by the admin for the provided {@code policyDefinition} and
+ * Retrieves the global policy set by the admin for the provided {@code policyDefinition}
* if one was set, otherwise returns {@code null}.
*/
@Nullable
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/flags/flags.aconfig b/services/devicepolicy/java/com/android/server/devicepolicy/flags/flags.aconfig
index aff1876..00702a9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/flags/flags.aconfig
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/flags/flags.aconfig
@@ -2,7 +2,7 @@
flag {
name: "policy_engine_migration_v2_enabled"
- namespace: "device_policy"
+ namespace: "enterprise"
description: "V2 of the policy engine migrations for Android V"
bug: "289520697"
}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
index 20d5f93..78d3a9d 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
@@ -147,6 +148,24 @@
verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
}
+ @Test
+ public void testWhenListenerIsNull() {
+ final AidlSession aidl = new AidlSession(0, mHal, USER_ID, mHalSessionCallback);
+ final FingerprintDetectClient client = new FingerprintDetectClient(mContext, () -> aidl,
+ mToken, 6 /* requestId */, null /* listener */,
+ new FingerprintAuthenticateOptions.Builder()
+ .setUserId(2)
+ .setSensorId(1)
+ .setOpPackageName("a-test")
+ .build(),
+ mBiometricLogger, mBiometricContext,
+ mUdfpsOverlayController, true /* isStrongBiometric */);
+ client.start(mCallback);
+ client.onInteractionDetected();
+
+ verify(mCallback).onClientFinished(eq(client), anyBoolean());
+ }
+
private FingerprintDetectClient createClient() throws RemoteException {
return createClient(200 /* version */);
}
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 42e3383..d6a3877 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -47,6 +47,8 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"/>
+ <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
+
<!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
<application android:debuggable="true"
@@ -104,6 +106,11 @@
android:showWhenLocked="true"
android:turnScreenOn="true" />
+ <activity android:name="android.app.Activity"
+ android:exported="true"
+ android:showWhenLocked="true"
+ android:turnScreenOn="true" />
+
<activity
android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity"
android:exported="true">
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 31682bc..ae58700 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -517,7 +517,7 @@
// The configuration change is still sent to the activity, even if it doesn't relaunch.
final ActivityConfigurationChangeItem expected =
- ActivityConfigurationChangeItem.obtain(newConfig);
+ ActivityConfigurationChangeItem.obtain(activity.token, newConfig);
verify(mAtm.getLifecycleManager()).scheduleTransaction(
eq(activity.app.getThread()), eq(activity.token), eq(expected));
}
@@ -597,7 +597,7 @@
activity.setRequestedOrientation(requestedOrientation);
final ActivityConfigurationChangeItem expected =
- ActivityConfigurationChangeItem.obtain(newConfig);
+ ActivityConfigurationChangeItem.obtain(activity.token, newConfig);
verify(mAtm.getLifecycleManager()).scheduleTransaction(eq(activity.app.getThread()),
eq(activity.token), eq(expected));
@@ -815,7 +815,7 @@
false /* preserveWindow */, true /* ignoreStopState */);
final ActivityConfigurationChangeItem expected =
- ActivityConfigurationChangeItem.obtain(newConfig);
+ ActivityConfigurationChangeItem.obtain(activity.token, newConfig);
verify(mAtm.getLifecycleManager()).scheduleTransaction(
eq(activity.app.getThread()), eq(activity.token), eq(expected));
} finally {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
index 769a309..1b44c01 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
@@ -573,8 +573,9 @@
final ClientTransaction transaction = ClientTransaction.obtain(
mActivity.app.getThread(), mActivity.token);
- transaction.addCallback(RefreshCallbackItem.obtain(cycleThroughStop ? ON_STOP : ON_PAUSE));
- transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(
+ transaction.addCallback(RefreshCallbackItem.obtain(mActivity.token,
+ cycleThroughStop ? ON_STOP : ON_PAUSE));
+ transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(mActivity.token,
/* isForward */ false, /* shouldSendCompatFakeFocus */ false));
verify(mActivity.mAtmService.getLifecycleManager(), times(refreshRequested ? 1 : 0))
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java
index 80e169d..be3f01e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java
@@ -17,14 +17,15 @@
package com.android.server.wm;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR;
+import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
-
+import static junit.framework.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -37,6 +38,8 @@
import androidx.test.filters.SmallTest;
+import com.android.window.flags.FakeFeatureFlagsImpl;
+
import org.junit.Before;
import org.junit.Test;
@@ -57,12 +60,16 @@
private LetterboxConfiguration mLetterboxConfiguration;
private LetterboxConfigurationPersister mLetterboxConfigurationPersister;
+ private MutableFakeFeatureFlagsImpl mMutableFakeFeatureFlags;
+
+
@Before
public void setUp() throws Exception {
mContext = getInstrumentation().getTargetContext();
+ mMutableFakeFeatureFlags = new MutableFakeFeatureFlagsImpl();
mLetterboxConfigurationPersister = mock(LetterboxConfigurationPersister.class);
mLetterboxConfiguration = new LetterboxConfiguration(mContext,
- mLetterboxConfigurationPersister);
+ mLetterboxConfigurationPersister, mMutableFakeFeatureFlags);
}
@Test
@@ -92,6 +99,22 @@
}
@Test
+ public void test_whenFlagEnabled_wallpaperIsDefaultBackground() {
+ mMutableFakeFeatureFlags.setLetterboxBackgroundWallpaperFlag(true);
+ assertEquals(LETTERBOX_BACKGROUND_WALLPAPER,
+ mLetterboxConfiguration.getLetterboxBackgroundType());
+ assertEquals(1, mMutableFakeFeatureFlags.getInvocationCount());
+ }
+
+ @Test
+ public void test_whenFlagDisabled_solidColorIsDefaultBackground() {
+ mMutableFakeFeatureFlags.setLetterboxBackgroundWallpaperFlag(false);
+ assertEquals(LETTERBOX_BACKGROUND_SOLID_COLOR,
+ mLetterboxConfiguration.getLetterboxBackgroundType());
+ assertEquals(1, mMutableFakeFeatureFlags.getInvocationCount());
+ }
+
+ @Test
public void test_whenMovedHorizontally_updatePositionAccordingly() {
// Starting from center
assertForHorizontalMove(
@@ -288,4 +311,23 @@
false /* forTabletopMode */,
LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
}
+
+ private static class MutableFakeFeatureFlagsImpl extends FakeFeatureFlagsImpl {
+ private boolean mLetterboxBackgroundWallpaperFlag;
+ private int mInvocationCount;
+
+ public void setLetterboxBackgroundWallpaperFlag(boolean letterboxBackgroundWallpaperFlag) {
+ mLetterboxBackgroundWallpaperFlag = letterboxBackgroundWallpaperFlag;
+ }
+
+ @Override
+ public boolean letterboxBackgroundWallpaperFlag() {
+ mInvocationCount++;
+ return mLetterboxBackgroundWallpaperFlag;
+ }
+
+ int getInvocationCount() {
+ return mInvocationCount;
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java
new file mode 100644
index 0000000..e8a847c
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TrustedOverlayTests.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.InputWindowHandle.USE_SURFACE_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.server.wm.BuildUtils;
+import android.server.wm.CtsWindowInfoUtils;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@Presubmit
+public class TrustedOverlayTests {
+ private static final String TAG = "TrustedOverlayTests";
+ private static final long TIMEOUT_S = 5L * BuildUtils.HW_TIMEOUT_MULTIPLIER;
+
+ @Rule
+ public TestName mName = new TestName();
+
+ private final ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(
+ Activity.class);
+
+ private Instrumentation mInstrumentation;
+ private Activity mActivity;
+
+ @Before
+ public void setup() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mActivity = mActivityRule.launchActivity(null);
+ }
+
+ @Test
+ public void setTrustedOverlayInputWindow() throws InterruptedException {
+ assumeFalse(USE_SURFACE_TRUSTED_OVERLAY);
+ testTrustedOverlayChildHelper(false);
+ }
+
+ @Test
+ public void setTrustedOverlayChildLayer() throws InterruptedException {
+ assumeTrue(USE_SURFACE_TRUSTED_OVERLAY);
+ testTrustedOverlayChildHelper(true);
+ }
+
+ private void testTrustedOverlayChildHelper(boolean expectTrusted) throws InterruptedException {
+ IBinder[] tokens = new IBinder[2];
+ CountDownLatch hostTokenReady = new CountDownLatch(1);
+ mInstrumentation.runOnMainSync(() -> {
+ mActivity.getWindow().addPrivateFlags(PRIVATE_FLAG_TRUSTED_OVERLAY);
+ View rootView = mActivity.getWindow().getDecorView();
+ if (rootView.isAttachedToWindow()) {
+ tokens[0] = rootView.getWindowToken();
+ hostTokenReady.countDown();
+ } else {
+ rootView.getViewTreeObserver().addOnWindowAttachListener(
+ new ViewTreeObserver.OnWindowAttachListener() {
+ @Override
+ public void onWindowAttached() {
+ tokens[0] = rootView.getWindowToken();
+ hostTokenReady.countDown();
+ }
+
+ @Override
+ public void onWindowDetached() {
+ }
+ });
+ }
+ });
+
+ assertTrue("Failed to wait for host to get added",
+ hostTokenReady.await(TIMEOUT_S, TimeUnit.SECONDS));
+
+ mInstrumentation.runOnMainSync(() -> {
+ WindowManager wm = mActivity.getSystemService(WindowManager.class);
+
+ View childView = new View(mActivity) {
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ tokens[1] = getWindowToken();
+ }
+ };
+ WindowManager.LayoutParams params = new WindowManager.LayoutParams();
+ params.token = tokens[0];
+ params.type = TYPE_APPLICATION_PANEL;
+ wm.addView(childView, params);
+ });
+
+ boolean[] foundTrusted = new boolean[2];
+
+ CtsWindowInfoUtils.waitForWindowInfos(
+ windowInfos -> {
+ for (var windowInfo : windowInfos) {
+ if (windowInfo.windowToken == tokens[0]
+ && windowInfo.isTrustedOverlay) {
+ foundTrusted[0] = true;
+ } else if (windowInfo.windowToken == tokens[1]
+ && windowInfo.isTrustedOverlay) {
+ foundTrusted[1] = true;
+ }
+ }
+ return foundTrusted[0] && foundTrusted[1];
+ }, TIMEOUT_S, TimeUnit.SECONDS);
+
+ if (!foundTrusted[0] || !foundTrusted[1]) {
+ CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, mName.getMethodName());
+ }
+
+ assertEquals("Failed to find parent window or was not marked trusted", expectTrusted,
+ foundTrusted[0]);
+ assertEquals("Failed to find child window or was not marked trusted", expectTrusted,
+ foundTrusted[1]);
+ }
+}