Merge "Add OWNERS file for mockingservicetests backup directory"
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index e928eb5..e6ddf9f 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -413,6 +413,7 @@
public final class DeviceConfig {
field public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager";
+ field public static final String NAMESPACE_APP_CLONING = "app_cloning";
field public static final String NAMESPACE_APP_STANDBY = "app_standby";
field public static final String NAMESPACE_DEVICE_IDLE = "device_idle";
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ce1eff1..001ebf5c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2909,6 +2909,7 @@
method @NonNull public java.util.Set<android.content.ComponentName> getBlockedCrossTaskNavigations();
method public int getDefaultActivityPolicy();
method public int getDefaultNavigationPolicy();
+ method public int getDevicePolicy(int);
method public int getLockState();
method @Nullable public String getName();
method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts();
@@ -2916,14 +2917,18 @@
field public static final int ACTIVITY_POLICY_DEFAULT_ALLOWED = 0; // 0x0
field public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1; // 0x1
field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDeviceParams> CREATOR;
+ field public static final int DEVICE_POLICY_CUSTOM = 1; // 0x1
+ field public static final int DEVICE_POLICY_DEFAULT = 0; // 0x0
field public static final int LOCK_STATE_ALWAYS_UNLOCKED = 1; // 0x1
field public static final int LOCK_STATE_DEFAULT = 0; // 0x0
field public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0; // 0x0
field public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1
+ field public static final int POLICY_TYPE_SENSORS = 0; // 0x0
}
public static final class VirtualDeviceParams.Builder {
ctor public VirtualDeviceParams.Builder();
+ method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder addDevicePolicy(int, int);
method @NonNull public android.companion.virtual.VirtualDeviceParams build();
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedActivities(@NonNull java.util.Set<android.content.ComponentName>);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>);
diff --git a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
index 82d7534..7d6336a 100644
--- a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
+++ b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
@@ -52,6 +52,11 @@
List<VirtualDevice> getVirtualDevices();
/**
+ * Returns the device policy for the given virtual device and policy type.
+ */
+ int getDevicePolicy(int deviceId, int policyType);
+
+ /**
* Creates a virtual display owned by a particular virtual device.
*
* @param virtualDisplayConfig The configuration used in creating the display
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 0bb86fb..c14bb1b 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -182,6 +182,28 @@
}
/**
+ * Returns the device policy for the given virtual device and policy type.
+ *
+ * <p>In case the virtual device identifier is not valid, or there's no explicitly specified
+ * policy for that device and policy type, then
+ * {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT} is returned.
+ *
+ * @hide
+ */
+ public @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
+ int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
+ if (mService == null) {
+ Log.w(TAG, "Failed to retrieve device policy; no virtual device manager service.");
+ return VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
+ }
+ try {
+ return mService.getDevicePolicy(deviceId, policyType);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* A virtual device has its own virtual display, audio output, microphone, and camera etc. The
* creator of a virtual device can take the output from the virtual display and stream it over
* to another device, and inject input events that are received from the remote device.
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index d40c9d6..c6e6f83 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -28,6 +28,7 @@
import android.os.Parcelable;
import android.os.UserHandle;
import android.util.ArraySet;
+import android.util.SparseIntArray;
import com.android.internal.util.Preconditions;
@@ -103,6 +104,47 @@
*/
public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1;
+ /** @hide */
+ @IntDef(prefix = "DEVICE_POLICY_", value = {DEVICE_POLICY_DEFAULT, DEVICE_POLICY_CUSTOM})
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ public @interface DevicePolicy {}
+
+ /**
+ * Indicates that there is no special logic for this virtual device and it should be treated
+ * the same way as the default device, keeping the default behavior unchanged.
+ */
+ public static final int DEVICE_POLICY_DEFAULT = 0;
+
+ /**
+ * Indicates that there is custom logic, specific to this virtual device, which should be
+ * triggered instead of the default behavior.
+ */
+ public static final int DEVICE_POLICY_CUSTOM = 1;
+
+ /**
+ * Any relevant component must be able to interpret the correct meaning of a custom policy for
+ * a given policy type.
+ * @hide
+ */
+ @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS})
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ public @interface PolicyType {}
+
+ /**
+ * Tells the sensor framework how to handle sensor requests from contexts associated with this
+ * virtual device, namely the sensors returned by
+ * {@link android.hardware.SensorManager#getSensorList}:
+ *
+ * <ul>
+ * <li>{@link #DEVICE_POLICY_DEFAULT}: Return the sensors of the default device.
+ * <li>{@link #DEVICE_POLICY_CUSTOM}: Return the sensors of the virtual device. Note that if
+ * the virtual device did not create any virtual sensors, then an empty list is returned.
+ * </ul>
+ */
+ public static final int POLICY_TYPE_SENSORS = 0;
+
private final int mLockState;
@NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
@NonNull private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
@@ -114,6 +156,8 @@
@ActivityPolicy
private final int mDefaultActivityPolicy;
@Nullable private final String mName;
+ // Mapping of @PolicyType to @DevicePolicy
+ @NonNull private final SparseIntArray mDevicePolicies;
private VirtualDeviceParams(
@LockState int lockState,
@@ -124,12 +168,14 @@
@NonNull Set<ComponentName> allowedActivities,
@NonNull Set<ComponentName> blockedActivities,
@ActivityPolicy int defaultActivityPolicy,
- @Nullable String name) {
+ @Nullable String name,
+ @NonNull SparseIntArray devicePolicies) {
Preconditions.checkNotNull(usersWithMatchingAccounts);
Preconditions.checkNotNull(allowedCrossTaskNavigations);
Preconditions.checkNotNull(blockedCrossTaskNavigations);
Preconditions.checkNotNull(allowedActivities);
Preconditions.checkNotNull(blockedActivities);
+ Preconditions.checkNotNull(devicePolicies);
mLockState = lockState;
mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts);
@@ -140,6 +186,7 @@
mBlockedActivities = new ArraySet<>(blockedActivities);
mDefaultActivityPolicy = defaultActivityPolicy;
mName = name;
+ mDevicePolicies = devicePolicies;
}
@SuppressWarnings("unchecked")
@@ -153,6 +200,7 @@
mBlockedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
mDefaultActivityPolicy = parcel.readInt();
mName = parcel.readString8();
+ mDevicePolicies = parcel.readSparseIntArray();
}
/**
@@ -258,6 +306,16 @@
return mName;
}
+ /**
+ * Returns the policy specified for this policy type, or {@link #DEVICE_POLICY_DEFAULT} if no
+ * policy for this type has been explicitly specified.
+ *
+ * @see Builder#addDevicePolicy
+ */
+ public @DevicePolicy int getDevicePolicy(@PolicyType int policyType) {
+ return mDevicePolicies.get(policyType, DEVICE_POLICY_DEFAULT);
+ }
+
@Override
public int describeContents() {
return 0;
@@ -274,6 +332,7 @@
dest.writeArraySet(mBlockedActivities);
dest.writeInt(mDefaultActivityPolicy);
dest.writeString8(mName);
+ dest.writeSparseIntArray(mDevicePolicies);
}
@Override
@@ -285,6 +344,18 @@
return false;
}
VirtualDeviceParams that = (VirtualDeviceParams) o;
+ final int devicePoliciesCount = mDevicePolicies.size();
+ if (devicePoliciesCount != that.mDevicePolicies.size()) {
+ return false;
+ }
+ for (int i = 0; i < devicePoliciesCount; i++) {
+ if (mDevicePolicies.keyAt(i) != that.mDevicePolicies.keyAt(i)) {
+ return false;
+ }
+ if (mDevicePolicies.valueAt(i) != that.mDevicePolicies.valueAt(i)) {
+ return false;
+ }
+ }
return mLockState == that.mLockState
&& mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts)
&& Objects.equals(mAllowedCrossTaskNavigations, that.mAllowedCrossTaskNavigations)
@@ -298,10 +369,15 @@
@Override
public int hashCode() {
- return Objects.hash(
+ int hashCode = Objects.hash(
mLockState, mUsersWithMatchingAccounts, mAllowedCrossTaskNavigations,
mBlockedCrossTaskNavigations, mDefaultNavigationPolicy, mAllowedActivities,
- mBlockedActivities, mDefaultActivityPolicy, mName);
+ mBlockedActivities, mDefaultActivityPolicy, mName, mDevicePolicies);
+ for (int i = 0; i < mDevicePolicies.size(); i++) {
+ hashCode = 31 * hashCode + mDevicePolicies.keyAt(i);
+ hashCode = 31 * hashCode + mDevicePolicies.valueAt(i);
+ }
+ return hashCode;
}
@Override
@@ -317,6 +393,7 @@
+ " mBlockedActivities=" + mBlockedActivities
+ " mDefaultActivityPolicy=" + mDefaultActivityPolicy
+ " mName=" + mName
+ + " mDevicePolicies=" + mDevicePolicies
+ ")";
}
@@ -350,6 +427,7 @@
private int mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
private boolean mDefaultActivityPolicyConfigured = false;
@Nullable private String mName;
+ @NonNull private SparseIntArray mDevicePolicies = new SparseIntArray();
/**
* Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY}
@@ -528,6 +606,18 @@
}
/**
+ * Specifies a policy for this virtual device.
+ *
+ * @param policyType the type of policy, i.e. which behavior to specify a policy for.
+ * @param devicePolicy the value of the policy, i.e. how to interpret the device behavior.
+ */
+ @NonNull
+ public Builder addDevicePolicy(@PolicyType int policyType, @DevicePolicy int devicePolicy) {
+ mDevicePolicies.put(policyType, devicePolicy);
+ return this;
+ }
+
+ /**
* Builds the {@link VirtualDeviceParams} instance.
*/
@NonNull
@@ -541,7 +631,8 @@
mAllowedActivities,
mBlockedActivities,
mDefaultActivityPolicy,
- mName);
+ mName,
+ mDevicePolicies);
}
}
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 7095d1b..6eeb5e7 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -131,6 +131,13 @@
public static final String NAMESPACE_APP_STANDBY = "app_standby";
/**
+ * Namespace for all App Cloning related features.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final String NAMESPACE_APP_CLONING = "app_cloning";
+
+ /**
* Namespace for AttentionManagerService related features.
*
* @hide
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index b24303b..720813a 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1073,7 +1073,7 @@
private void handleSyncBufferCallback(SurfaceHolder.Callback[] callbacks,
SyncBufferTransactionCallback syncBufferTransactionCallback) {
- getViewRootImpl().addToSync(syncBufferCallback ->
+ getViewRootImpl().addToSync((parentSyncGroup, syncBufferCallback) ->
redrawNeededAsync(callbacks, () -> {
Transaction t = null;
if (mBlastBufferQueue != null) {
@@ -1081,7 +1081,7 @@
t = syncBufferTransactionCallback.waitForTransaction();
}
- syncBufferCallback.onBufferReady(t);
+ syncBufferCallback.onTransactionReady(t);
onDrawFinished();
}));
}
@@ -1092,9 +1092,9 @@
mSyncGroups.add(syncGroup);
}
- syncGroup.addToSync(syncBufferCallback -> redrawNeededAsync(callbacks,
- () -> {
- syncBufferCallback.onBufferReady(null);
+ syncGroup.addToSync((parentSyncGroup, syncBufferCallback) ->
+ redrawNeededAsync(callbacks, () -> {
+ syncBufferCallback.onTransactionReady(null);
onDrawFinished();
synchronized (mSyncGroups) {
mSyncGroups.remove(syncGroup);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7e8ebd7..5e1dc34 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -231,6 +231,7 @@
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
/**
* The top of a view hierarchy, implementing the needed protocol between View
@@ -851,7 +852,7 @@
}
private SurfaceSyncGroup mSyncGroup;
- private SurfaceSyncGroup.SyncBufferCallback mSyncBufferCallback;
+ private SurfaceSyncGroup.TransactionReadyCallback mTransactionReadyCallback;
private int mNumSyncsInProgress = 0;
private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
@@ -3610,8 +3611,8 @@
mPendingTransitions.clear();
}
- if (mSyncBufferCallback != null) {
- mSyncBufferCallback.onBufferReady(null);
+ if (mTransactionReadyCallback != null) {
+ mTransactionReadyCallback.onTransactionReady(null);
}
} else if (cancelAndRedraw) {
mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
@@ -3626,8 +3627,8 @@
}
mPendingTransitions.clear();
}
- if (!performDraw() && mSyncBufferCallback != null) {
- mSyncBufferCallback.onBufferReady(null);
+ if (!performDraw() && mTransactionReadyCallback != null) {
+ mTransactionReadyCallback.onTransactionReady(null);
}
}
@@ -3641,7 +3642,7 @@
if (!cancelAndRedraw) {
mReportNextDraw = false;
mLastReportNextDrawReason = null;
- mSyncBufferCallback = null;
+ mTransactionReadyCallback = null;
mSyncBuffer = false;
if (isInLocalSync()) {
mSyncGroup.markSyncReady();
@@ -4388,7 +4389,7 @@
return false;
}
- final boolean fullRedrawNeeded = mFullRedrawNeeded || mSyncBufferCallback != null;
+ final boolean fullRedrawNeeded = mFullRedrawNeeded || mTransactionReadyCallback != null;
mFullRedrawNeeded = false;
mIsDrawing = true;
@@ -4396,9 +4397,9 @@
addFrameCommitCallbackIfNeeded();
- boolean usingAsyncReport = isHardwareEnabled() && mSyncBufferCallback != null;
+ boolean usingAsyncReport = isHardwareEnabled() && mTransactionReadyCallback != null;
if (usingAsyncReport) {
- registerCallbacksForSync(mSyncBuffer, mSyncBufferCallback);
+ registerCallbacksForSync(mSyncBuffer, mTransactionReadyCallback);
} else if (mHasPendingTransactions) {
// These callbacks are only needed if there's no sync involved and there were calls to
// applyTransactionOnDraw. These callbacks check if the draw failed for any reason and
@@ -4449,10 +4450,11 @@
}
if (mSurfaceHolder != null && mSurface.isValid()) {
- final SurfaceSyncGroup.SyncBufferCallback syncBufferCallback = mSyncBufferCallback;
+ final SurfaceSyncGroup.TransactionReadyCallback transactionReadyCallback =
+ mTransactionReadyCallback;
SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() ->
- mHandler.post(() -> syncBufferCallback.onBufferReady(null)));
- mSyncBufferCallback = null;
+ mHandler.post(() -> transactionReadyCallback.onTransactionReady(null)));
+ mTransactionReadyCallback = null;
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
@@ -4463,8 +4465,8 @@
}
}
}
- if (mSyncBufferCallback != null && !usingAsyncReport) {
- mSyncBufferCallback.onBufferReady(null);
+ if (mTransactionReadyCallback != null && !usingAsyncReport) {
+ mTransactionReadyCallback.onTransactionReady(null);
}
if (mPerformContentCapture) {
performContentCaptureInitialReport();
@@ -11134,7 +11136,7 @@
}
private void registerCallbacksForSync(boolean syncBuffer,
- final SurfaceSyncGroup.SyncBufferCallback syncBufferCallback) {
+ final SurfaceSyncGroup.TransactionReadyCallback transactionReadyCallback) {
if (!isHardwareEnabled()) {
return;
}
@@ -11161,7 +11163,7 @@
// pendingDrawFinished.
if ((syncResult
& (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
- syncBufferCallback.onBufferReady(
+ transactionReadyCallback.onTransactionReady(
mBlastBufferQueue.gatherPendingTransactions(frame));
return null;
}
@@ -11171,7 +11173,8 @@
}
if (syncBuffer) {
- mBlastBufferQueue.syncNextTransaction(syncBufferCallback::onBufferReady);
+ mBlastBufferQueue.syncNextTransaction(
+ transactionReadyCallback::onTransactionReady);
}
return didProduceBuffer -> {
@@ -11191,7 +11194,7 @@
// since the frame didn't draw on this vsync. It's possible the frame will
// draw later, but it's better to not be sync than to block on a frame that
// may never come.
- syncBufferCallback.onBufferReady(
+ transactionReadyCallback.onTransactionReady(
mBlastBufferQueue.gatherPendingTransactions(frame));
return;
}
@@ -11200,22 +11203,49 @@
// syncNextTransaction callback. Instead, just report back to the Syncer so it
// knows that this sync request is complete.
if (!syncBuffer) {
- syncBufferCallback.onBufferReady(null);
+ transactionReadyCallback.onTransactionReady(null);
}
};
}
});
}
+ private final Executor mPostAtFrontExecutor = new Executor() {
+ @Override
+ public void execute(Runnable command) {
+ mHandler.postAtFrontOfQueue(command);
+ }
+ };
+
public final SurfaceSyncGroup.SyncTarget mSyncTarget = new SurfaceSyncGroup.SyncTarget() {
@Override
- public void onReadyToSync(SurfaceSyncGroup.SyncBufferCallback syncBufferCallback) {
- readyToSync(syncBufferCallback);
+ public void onAddedToSyncGroup(SurfaceSyncGroup parentSyncGroup,
+ SurfaceSyncGroup.TransactionReadyCallback transactionReadyCallback) {
+ updateSyncInProgressCount(parentSyncGroup);
+ if (!isInLocalSync()) {
+ // Always sync the buffer if the sync request did not come from VRI.
+ mSyncBuffer = true;
+ }
+ if (mAttachInfo.mThreadedRenderer != null) {
+ HardwareRenderer.setRtAnimationsEnabled(false);
+ }
+
+ if (mTransactionReadyCallback != null) {
+ Log.d(mTag, "Already set sync for the next draw.");
+ mTransactionReadyCallback.onTransactionReady(null);
+ }
+ if (DEBUG_BLAST) {
+ Log.d(mTag, "Setting syncFrameCallback");
+ }
+ mTransactionReadyCallback = transactionReadyCallback;
+ if (!mIsInTraversal && !mTraversalScheduled) {
+ scheduleTraversals();
+ }
}
- @Override
- public void onSyncComplete() {
- mHandler.postAtFrontOfQueue(() -> {
+ private void updateSyncInProgressCount(SurfaceSyncGroup parentSyncGroup) {
+ mNumSyncsInProgress++;
+ parentSyncGroup.addSyncCompleteCallback(mPostAtFrontExecutor, () -> {
if (--mNumSyncsInProgress == 0 && mAttachInfo.mThreadedRenderer != null) {
HardwareRenderer.setRtAnimationsEnabled(true);
}
@@ -11228,29 +11258,6 @@
return mSyncTarget;
}
- private void readyToSync(SurfaceSyncGroup.SyncBufferCallback syncBufferCallback) {
- mNumSyncsInProgress++;
- if (!isInLocalSync()) {
- // Always sync the buffer if the sync request did not come from VRI.
- mSyncBuffer = true;
- }
- if (mAttachInfo.mThreadedRenderer != null) {
- HardwareRenderer.setRtAnimationsEnabled(false);
- }
-
- if (mSyncBufferCallback != null) {
- Log.d(mTag, "Already set sync for the next draw.");
- mSyncBufferCallback.onBufferReady(null);
- }
- if (DEBUG_BLAST) {
- Log.d(mTag, "Setting syncFrameCallback");
- }
- mSyncBufferCallback = syncBufferCallback;
- if (!mIsInTraversal && !mTraversalScheduled) {
- scheduleTraversals();
- }
- }
-
void mergeSync(SurfaceSyncGroup otherSyncGroup) {
if (!isInLocalSync()) {
return;
diff --git a/core/java/android/window/SurfaceSyncGroup.java b/core/java/android/window/SurfaceSyncGroup.java
index 4248096..3950739 100644
--- a/core/java/android/window/SurfaceSyncGroup.java
+++ b/core/java/android/window/SurfaceSyncGroup.java
@@ -57,12 +57,13 @@
* option is provided.
*
* The following is what happens within the {@link SurfaceSyncGroup}
- * 1. Each SyncTarget will get a {@link SyncTarget#onReadyToSync} callback that contains a
- * {@link SyncBufferCallback}.
- * 2. Each {@link SyncTarget} needs to invoke {@link SyncBufferCallback#onBufferReady(Transaction)}.
- * This makes sure the SurfaceSyncGroup knows when the SyncTarget is complete, allowing the
- * SurfaceSyncGroup to get the Transaction that contains the buffer.
- * 3. When the final SyncBufferCallback finishes for the SurfaceSyncGroup, in most cases the
+ * 1. Each SyncTarget will get a {@link SyncTarget#onAddedToSyncGroup} callback that contains a
+ * {@link TransactionReadyCallback}.
+ * 2. Each {@link SyncTarget} needs to invoke
+ * {@link TransactionReadyCallback#onTransactionReady(Transaction)}. This makes sure the
+ * SurfaceSyncGroup knows when the SyncTarget is complete, allowing the SurfaceSyncGroup to get the
+ * Transaction that contains the buffer.
+ * 3. When the final TransactionReadyCallback finishes for the SurfaceSyncGroup, in most cases the
* transaction is applied and then the sync complete callbacks are invoked, letting the callers know
* the sync is now complete.
*
@@ -86,8 +87,6 @@
private final Transaction mTransaction = sTransactionFactory.get();
@GuardedBy("mLock")
private boolean mSyncReady;
- @GuardedBy("mLock")
- private final Set<SyncTarget> mSyncTargets = new ArraySet<>();
@GuardedBy("mLock")
private Consumer<Transaction> mSyncRequestCompleteCallback;
@@ -197,14 +196,13 @@
* Add a {@link SyncTarget} to a sync set. The sync set will wait for all
* SyncableSurfaces to complete before notifying.
*
- * @param syncTarget A SyncableSurface that implements how to handle syncing
- * buffers.
+ * @param syncTarget A SyncTarget that implements how to handle syncing transactions.
* @return true if the SyncTarget was successfully added to the SyncGroup, false otherwise.
*/
public boolean addToSync(SyncTarget syncTarget) {
- SyncBufferCallback syncBufferCallback = new SyncBufferCallback() {
+ TransactionReadyCallback transactionReadyCallback = new TransactionReadyCallback() {
@Override
- public void onBufferReady(Transaction t) {
+ public void onTransactionReady(Transaction t) {
synchronized (mLock) {
if (t != null) {
mTransaction.merge(t);
@@ -221,10 +219,9 @@
+ "SyncTargets can be added.");
return false;
}
- mPendingSyncs.add(syncBufferCallback.hashCode());
- mSyncTargets.add(syncTarget);
+ mPendingSyncs.add(transactionReadyCallback.hashCode());
}
- syncTarget.onReadyToSync(syncBufferCallback);
+ syncTarget.onAddedToSyncGroup(this, transactionReadyCallback);
return true;
}
@@ -256,17 +253,13 @@
Log.d(TAG, "Successfully finished sync id=" + this);
}
- for (SyncTarget syncTarget : mSyncTargets) {
- syncTarget.onSyncComplete();
- }
- mSyncTargets.clear();
mSyncRequestCompleteCallback.accept(mTransaction);
mFinished = true;
}
/**
* Add a Transaction to this sync set. This allows the caller to provide other info that
- * should be synced with the buffers.
+ * should be synced with the transactions.
*/
public void addTransactionToSync(Transaction t) {
synchronized (mLock) {
@@ -334,9 +327,10 @@
}
@Override
- public void onReadyToSync(SyncBufferCallback syncBufferCallback) {
+ public void onAddedToSyncGroup(SurfaceSyncGroup parentSyncGroup,
+ TransactionReadyCallback transactionReadyCallback) {
mFrameCallbackConsumer.accept(
- () -> mSurfaceView.syncNextFrame(syncBufferCallback::onBufferReady));
+ () -> mSurfaceView.syncNextFrame(transactionReadyCallback::onTransactionReady));
}
}
@@ -345,22 +339,19 @@
*/
public interface SyncTarget {
/**
- * Called when the Syncable is ready to begin handing a sync request. When invoked, the
- * implementor is required to call {@link SyncBufferCallback#onBufferReady(Transaction)}
- * and {@link SyncBufferCallback#onBufferReady(Transaction)} in order for this Syncable
- * to be marked as complete.
+ * Called when the SyncTarget has been added to a SyncGroup as is ready to begin handing a
+ * sync request. When invoked, the implementor is required to call
+ * {@link TransactionReadyCallback#onTransactionReady(Transaction)} in order for this
+ * SurfaceSyncGroup to fully complete.
*
* Always invoked on the thread that initiated the call to {@link #addToSync(SyncTarget)}
*
- * @param syncBufferCallback A SyncBufferCallback that the caller must invoke onBufferReady
+ * @param parentSyncGroup The sync group this target has been added to.
+ * @param transactionReadyCallback A TransactionReadyCallback that the caller must invoke
+ * onTransactionReady
*/
- void onReadyToSync(SyncBufferCallback syncBufferCallback);
-
- /**
- * There's no guarantee about the thread this callback is invoked on.
- */
- default void onSyncComplete() {
- }
+ void onAddedToSyncGroup(SurfaceSyncGroup parentSyncGroup,
+ TransactionReadyCallback transactionReadyCallback);
}
/**
@@ -368,14 +359,14 @@
* completed. The caller should invoke the calls when the rendering has started and finished a
* frame.
*/
- public interface SyncBufferCallback {
+ public interface TransactionReadyCallback {
/**
- * Invoked when the transaction contains the buffer and is ready to sync.
+ * Invoked when the transaction is ready to sync.
*
- * @param t The transaction that contains the buffer to be synced. This can be null if
- * there's nothing to sync
+ * @param t The transaction that contains the anything to be included in the synced. This
+ * can be null if there's nothing to sync
*/
- void onBufferReady(@Nullable Transaction t);
+ void onTransactionReady(@Nullable Transaction t);
}
/**
diff --git a/core/res/res/anim/dock_bottom_enter.xml b/core/res/res/anim/dock_bottom_enter.xml
deleted file mode 100644
index bfb97b6..0000000
--- a/core/res/res/anim/dock_bottom_enter.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 2012, 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.
-*/
--->
-
-<!-- Animation for when a dock window at the bottom of the screen is entering. -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:interpolator/decelerate_cubic">
- <translate android:fromYDelta="100%" android:toYDelta="0"
- android:duration="@integer/dock_enter_exit_duration"/>
-</set>
diff --git a/core/res/res/anim/dock_bottom_exit.xml b/core/res/res/anim/dock_bottom_exit.xml
deleted file mode 100644
index 4e15448..0000000
--- a/core/res/res/anim/dock_bottom_exit.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 2012, 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.
-*/
--->
-
-<!-- Animation for when a dock window at the bottom of the screen is exiting. -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:interpolator/accelerate_cubic">
- <translate android:fromYDelta="0" android:toYDelta="100%"
- android:startOffset="100" android:duration="@integer/dock_enter_exit_duration"/>
-</set>
diff --git a/core/res/res/anim/dock_bottom_exit_keyguard.xml b/core/res/res/anim/dock_bottom_exit_keyguard.xml
deleted file mode 100644
index 4de3ce5..0000000
--- a/core/res/res/anim/dock_bottom_exit_keyguard.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
- ~ Copyright (C) 2016 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<!-- Animation for when a dock window at the bottom of the screen is exiting while on Keyguard -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:interpolator/fast_out_linear_in">
- <translate android:fromYDelta="0" android:toYDelta="100%"
- android:duration="200"/>
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim/dock_left_enter.xml b/core/res/res/anim/dock_left_enter.xml
deleted file mode 100644
index 7f5dfd5..0000000
--- a/core/res/res/anim/dock_left_enter.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 2012, 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.
-*/
--->
-
-<!-- Animation for when a dock window at the left of the screen is entering. -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:interpolator/decelerate_cubic">
- <translate android:fromXDelta="-100%" android:toXDelta="0"
- android:duration="250"/>
-</set>
diff --git a/core/res/res/anim/dock_left_exit.xml b/core/res/res/anim/dock_left_exit.xml
deleted file mode 100644
index 11cbc0b3..0000000
--- a/core/res/res/anim/dock_left_exit.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 2012, 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.
-*/
--->
-
-<!-- Animation for when a dock window at the right of the screen is exiting. -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:interpolator/accelerate_cubic">
- <translate android:fromXDelta="0" android:toXDelta="-100%"
- android:startOffset="100" android:duration="250"/>
-</set>
diff --git a/core/res/res/anim/dock_right_enter.xml b/core/res/res/anim/dock_right_enter.xml
deleted file mode 100644
index a92c7d2..0000000
--- a/core/res/res/anim/dock_right_enter.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 2012, 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.
-*/
--->
-
-<!-- Animation for when a dock window at the right of the screen is entering. -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:interpolator/decelerate_cubic">
- <translate android:fromXDelta="100%" android:toXDelta="0"
- android:duration="250"/>
-</set>
diff --git a/core/res/res/anim/dock_right_exit.xml b/core/res/res/anim/dock_right_exit.xml
deleted file mode 100644
index 80e4dc3..0000000
--- a/core/res/res/anim/dock_right_exit.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 2012, 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.
-*/
--->
-
-<!-- Animation for when a dock window at the right of the screen is exiting. -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:interpolator/accelerate_cubic">
- <translate android:fromXDelta="0" android:toXDelta="100%"
- android:startOffset="100" android:duration="250"/>
-</set>
diff --git a/core/res/res/anim/dock_top_enter.xml b/core/res/res/anim/dock_top_enter.xml
deleted file mode 100644
index f763fb5..0000000
--- a/core/res/res/anim/dock_top_enter.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 2007, 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.
-*/
--->
-
-<!-- Animation for when a dock window at the top of the screen is entering. -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:interpolator/decelerate_cubic">
- <translate android:fromYDelta="-100%" android:toYDelta="0"
- android:duration="@integer/dock_enter_exit_duration"/>
-</set>
diff --git a/core/res/res/anim/dock_top_exit.xml b/core/res/res/anim/dock_top_exit.xml
deleted file mode 100644
index 995b7d0..0000000
--- a/core/res/res/anim/dock_top_exit.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 2007, 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.
-*/
--->
-
-<!-- Animation for when a dock window at the top of the screen is exiting. -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:interpolator/accelerate_cubic">
- <translate android:fromYDelta="0" android:toYDelta="-100%"
- android:startOffset="100" android:duration="@integer/dock_enter_exit_duration"/>
-</set>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 89ec5ba..437dedc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1691,15 +1691,6 @@
<!-- From android.policy -->
<java-symbol type="anim" name="app_starting_exit" />
- <java-symbol type="anim" name="dock_top_enter" />
- <java-symbol type="anim" name="dock_top_exit" />
- <java-symbol type="anim" name="dock_bottom_enter" />
- <java-symbol type="anim" name="dock_bottom_exit" />
- <java-symbol type="anim" name="dock_bottom_exit_keyguard" />
- <java-symbol type="anim" name="dock_left_enter" />
- <java-symbol type="anim" name="dock_left_exit" />
- <java-symbol type="anim" name="dock_right_enter" />
- <java-symbol type="anim" name="dock_right_exit" />
<java-symbol type="anim" name="fade_in" />
<java-symbol type="anim" name="fade_out" />
<java-symbol type="anim" name="voice_activity_close_exit" />
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 07cd7d6..f811940 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -116,7 +116,7 @@
private final TouchTracker mTouchTracker = new TouchTracker();
private final SparseArray<BackAnimationRunner> mAnimationDefinition = new SparseArray<>();
-
+ @Nullable
private IOnBackInvokedCallback mActiveCallback;
@VisibleForTesting
@@ -180,6 +180,10 @@
}
private void initBackAnimationRunners() {
+ if (!IS_U_ANIMATION_ENABLED) {
+ return;
+ }
+
final CrossTaskBackAnimation crossTaskAnimation = new CrossTaskBackAnimation(mContext);
mAnimationDefinition.set(BackNavigationInfo.TYPE_CROSS_TASK,
new BackAnimationRunner(crossTaskAnimation.mCallback, crossTaskAnimation.mRunner));
@@ -207,7 +211,7 @@
private void updateEnableAnimationFromSetting() {
int settingValue = Global.getInt(mContext.getContentResolver(),
Global.ENABLE_BACK_ANIMATION, SETTING_VALUE_OFF);
- boolean isEnabled = settingValue == SETTING_VALUE_ON && IS_U_ANIMATION_ENABLED;
+ boolean isEnabled = settingValue == SETTING_VALUE_ON;
mEnableAnimations.set(isEnabled);
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Back animation enabled=%s", isEnabled);
}
@@ -350,10 +354,14 @@
return;
}
final int backType = backNavigationInfo.getType();
- final boolean shouldDispatchToAnimator = shouldDispatchToAnimator(backType);
+ final boolean shouldDispatchToAnimator = shouldDispatchToAnimator();
if (shouldDispatchToAnimator) {
- mActiveCallback = mAnimationDefinition.get(backType).getCallback();
- mAnimationDefinition.get(backType).startGesture();
+ if (mAnimationDefinition.contains(backType)) {
+ mActiveCallback = mAnimationDefinition.get(backType).getCallback();
+ mAnimationDefinition.get(backType).startGesture();
+ } else {
+ mActiveCallback = null;
+ }
} else {
mActiveCallback = mBackNavigationInfo.getOnBackInvokedCallback();
dispatchOnBackStarted(mActiveCallback, mTouchTracker.createStartEvent(null));
@@ -361,9 +369,11 @@
}
private void onMove() {
- if (!mBackGestureStarted || mBackNavigationInfo == null || !mEnableAnimations.get()) {
+ if (!mBackGestureStarted || mBackNavigationInfo == null || !mEnableAnimations.get()
+ || mActiveCallback == null) {
return;
}
+
final BackEvent backEvent = mTouchTracker.createProgressEvent();
dispatchOnBackProgressed(mActiveCallback, backEvent);
}
@@ -387,11 +397,10 @@
}
}
- private boolean shouldDispatchToAnimator(int backType) {
+ private boolean shouldDispatchToAnimator() {
return mEnableAnimations.get()
&& mBackNavigationInfo != null
- && mBackNavigationInfo.isPrepareRemoteAnimation()
- && mAnimationDefinition.contains(backType);
+ && mBackNavigationInfo.isPrepareRemoteAnimation();
}
private void dispatchOnBackStarted(IOnBackInvokedCallback callback,
@@ -461,6 +470,30 @@
mTouchTracker.setProgressThreshold(progressThreshold);
}
+ private void invokeOrCancelBack() {
+ // Make a synchronized call to core before dispatch back event to client side.
+ // If the close transition happens before the core receives onAnimationFinished, there will
+ // play a second close animation for that transition.
+ if (mBackAnimationFinishedCallback != null) {
+ try {
+ mBackAnimationFinishedCallback.onAnimationFinished(mTriggerBack);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed call IBackAnimationFinishedCallback", e);
+ }
+ mBackAnimationFinishedCallback = null;
+ }
+
+ if (mBackNavigationInfo != null) {
+ final IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback();
+ if (mTriggerBack) {
+ dispatchOnBackInvoked(callback);
+ } else {
+ dispatchOnBackCancelled(callback);
+ }
+ }
+ finishBackNavigation();
+ }
+
/**
* Called when the gesture is released, then it could start the post commit animation.
*/
@@ -493,15 +526,9 @@
}
final int backType = mBackNavigationInfo.getType();
- // Directly finish back navigation if no animator defined.
- if (!shouldDispatchToAnimator(backType)) {
- if (mTriggerBack) {
- dispatchOnBackInvoked(mActiveCallback);
- } else {
- dispatchOnBackCancelled(mActiveCallback);
- }
- // Animation missing. Simply finish back navigation.
- finishBackNavigation();
+ // Simply trigger and finish back navigation when no animator defined.
+ if (!shouldDispatchToAnimator() || mActiveCallback == null) {
+ invokeOrCancelBack();
return;
}
@@ -549,16 +576,7 @@
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: onBackAnimationFinished()");
// Trigger the real back.
- if (mBackNavigationInfo != null) {
- IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback();
- if (mTriggerBack) {
- dispatchOnBackInvoked(callback);
- } else {
- dispatchOnBackCancelled(callback);
- }
- }
-
- finishBackNavigation();
+ invokeOrCancelBack();
}
/**
@@ -567,25 +585,14 @@
@VisibleForTesting
void finishBackNavigation() {
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishBackNavigation()");
- BackNavigationInfo backNavigationInfo = mBackNavigationInfo;
- boolean triggerBack = mTriggerBack;
- mBackNavigationInfo = null;
- mTriggerBack = false;
mShouldStartOnNextMoveEvent = false;
mTouchTracker.reset();
mActiveCallback = null;
- if (backNavigationInfo == null) {
- return;
+ if (mBackNavigationInfo != null) {
+ mBackNavigationInfo.onBackNavigationFinished(mTriggerBack);
+ mBackNavigationInfo = null;
}
- if (mBackAnimationFinishedCallback != null) {
- try {
- mBackAnimationFinishedCallback.onAnimationFinished(triggerBack);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed call IBackAnimationFinishedCallback", e);
- }
- mBackAnimationFinishedCallback = null;
- }
- backNavigationInfo.onBackNavigationFinished(triggerBack);
+ mTriggerBack = false;
}
private void createAdapter() {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index b603e03..d75c36c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -38,6 +38,7 @@
import android.content.pm.ApplicationInfo;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteCallback;
@@ -56,6 +57,7 @@
import android.window.IBackAnimationFinishedCallback;
import android.window.IOnBackInvokedCallback;
+import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -189,31 +191,23 @@
}
for (int type: testTypes) {
- boolean[] backNavigationDone = new boolean[]{false};
- boolean[] triggerBack = new boolean[]{false};
-
+ final ResultListener result = new ResultListener();
createNavigationInfo(new BackNavigationInfo.Builder()
.setType(type)
.setOnBackInvokedCallback(mAppCallback)
.setPrepareRemoteAnimation(true)
- .setOnBackNavigationDone(
- new RemoteCallback(result -> {
- backNavigationDone[0] = true;
- triggerBack[0] = result.getBoolean(KEY_TRIGGER_BACK);
- })));
+ .setOnBackNavigationDone(new RemoteCallback(result)));
triggerBackGesture();
simulateRemoteAnimationStart(type);
simulateRemoteAnimationFinished();
mShellExecutor.flushAll();
assertTrue("Navigation Done callback not called for "
- + BackNavigationInfo.typeToString(type), backNavigationDone[0]);
- assertTrue("TriggerBack should have been true", triggerBack[0]);
+ + BackNavigationInfo.typeToString(type), result.mBackNavigationDone);
+ assertTrue("TriggerBack should have been true", result.mTriggerBack);
}
}
-
-
@Test
public void backToHome_dispatchesEvents() throws RemoteException {
registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
@@ -351,6 +345,65 @@
verify(mAnimatorCallback, never()).onBackInvoked();
}
+ @Test
+ public void animationNotDefined() throws RemoteException {
+ final int[] testTypes = new int[] {
+ BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ BackNavigationInfo.TYPE_CROSS_TASK,
+ BackNavigationInfo.TYPE_CROSS_ACTIVITY,
+ BackNavigationInfo.TYPE_DIALOG_CLOSE};
+
+ for (int type: testTypes) {
+ final ResultListener result = new ResultListener();
+ createNavigationInfo(new BackNavigationInfo.Builder()
+ .setType(type)
+ .setOnBackInvokedCallback(mAppCallback)
+ .setPrepareRemoteAnimation(true)
+ .setOnBackNavigationDone(new RemoteCallback(result)));
+ triggerBackGesture();
+ simulateRemoteAnimationStart(type);
+ mShellExecutor.flushAll();
+
+ assertTrue("Navigation Done callback not called for "
+ + BackNavigationInfo.typeToString(type), result.mBackNavigationDone);
+ assertTrue("TriggerBack should have been true", result.mTriggerBack);
+ }
+
+ verify(mAppCallback, never()).onBackStarted(any());
+ verify(mAppCallback, never()).onBackProgressed(any());
+ verify(mAppCallback, times(testTypes.length)).onBackInvoked();
+
+ verify(mAnimatorCallback, never()).onBackStarted(any());
+ verify(mAnimatorCallback, never()).onBackProgressed(any());
+ verify(mAnimatorCallback, never()).onBackInvoked();
+ }
+
+ @Test
+ public void callbackShouldDeliverProgress() throws RemoteException {
+ registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+
+ final int type = BackNavigationInfo.TYPE_CALLBACK;
+ final ResultListener result = new ResultListener();
+ createNavigationInfo(new BackNavigationInfo.Builder()
+ .setType(type)
+ .setOnBackInvokedCallback(mAppCallback)
+ .setOnBackNavigationDone(new RemoteCallback(result)));
+ triggerBackGesture();
+ mShellExecutor.flushAll();
+
+ assertTrue("Navigation Done callback not called for "
+ + BackNavigationInfo.typeToString(type), result.mBackNavigationDone);
+ assertTrue("TriggerBack should have been true", result.mTriggerBack);
+
+ verify(mAppCallback, times(1)).onBackStarted(any());
+ verify(mAppCallback, times(1)).onBackProgressed(any());
+ verify(mAppCallback, times(1)).onBackInvoked();
+
+ verify(mAnimatorCallback, never()).onBackStarted(any());
+ verify(mAnimatorCallback, never()).onBackProgressed(any());
+ verify(mAnimatorCallback, never()).onBackInvoked();
+ }
+
private void doMotionEvent(int actionDown, int coordinate) {
mController.onMotionEvent(
coordinate, coordinate,
@@ -377,4 +430,14 @@
mController.registerAnimation(type,
new BackAnimationRunner(mAnimatorCallback, mBackAnimationRunner));
}
+
+ private static class ResultListener implements RemoteCallback.OnResultListener {
+ boolean mBackNavigationDone = false;
+ boolean mTriggerBack = false;
+ @Override
+ public void onResult(@Nullable Bundle result) {
+ mBackNavigationDone = true;
+ mTriggerBack = result.getBoolean(KEY_TRIGGER_BACK);
+ }
+ };
}
diff --git a/packages/SystemUI/res/drawable/ic_watch.xml b/packages/SystemUI/res/drawable/ic_watch.xml
new file mode 100644
index 0000000..8ff880c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_watch.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M16,0L8,0l-0.95,5.73C5.19,7.19 4,9.45 4,12s1.19,4.81 3.05,6.27L8,24
+ h8l0.96,-5.73C18.81,16.81 20,14.54 20,12s-1.19,-4.81 -3.04,-6.27L16,0z
+ M12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6z"/>
+</vector>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index 8fa7b11..2b660de 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -21,7 +21,6 @@
import android.content.res.Resources;
import android.media.AudioManager;
import android.os.SystemClock;
-import android.service.trust.TrustAgentService;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.MathUtils;
@@ -68,30 +67,24 @@
private final KeyguardUpdateMonitorCallback mUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@Override
- public void onTrustGrantedWithFlags(int flags, int userId, String message) {
- if (userId != KeyguardUpdateMonitor.getCurrentUser()) return;
- boolean bouncerVisible = mView.isVisibleToUser();
- boolean temporaryAndRenewable =
- (flags & TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
- != 0;
- boolean initiatedByUser =
- (flags & TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER) != 0;
- boolean dismissKeyguard =
- (flags & TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD) != 0;
-
- if (initiatedByUser || dismissKeyguard) {
- if ((mViewMediatorCallback.isScreenOn() || temporaryAndRenewable)
- && (bouncerVisible || dismissKeyguard)) {
- if (!bouncerVisible) {
- // The trust agent dismissed the keyguard without the user proving
- // that they are present (by swiping up to show the bouncer). That's
- // fine if the user proved presence via some other way to the trust
- //agent.
- Log.i(TAG, "TrustAgent dismissed Keyguard.");
- }
- mSecurityCallback.dismiss(false /* authenticated */, userId,
- /* bypassSecondaryLockScreen */ false, SecurityMode.Invalid);
- } else {
+ public void onTrustGrantedForCurrentUser(boolean dismissKeyguard,
+ TrustGrantFlags flags, String message) {
+ if (dismissKeyguard) {
+ if (!mView.isVisibleToUser()) {
+ // The trust agent dismissed the keyguard without the user proving
+ // that they are present (by swiping up to show the bouncer). That's
+ // fine if the user proved presence via some other way to the trust
+ // agent.
+ Log.i(TAG, "TrustAgent dismissed Keyguard.");
+ }
+ mSecurityCallback.dismiss(
+ false /* authenticated */,
+ KeyguardUpdateMonitor.getCurrentUser(),
+ /* bypassSecondaryLockScreen */ false,
+ SecurityMode.Invalid
+ );
+ } else {
+ if (flags.isInitiatedByUser() || flags.dismissKeyguardRequested()) {
mViewMediatorCallback.playTrustedSound();
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index d694dc0..2d3dda9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -472,10 +472,12 @@
FACE_AUTH_TRIGGERED_TRUST_DISABLED);
}
- String message = null;
- if (KeyguardUpdateMonitor.getCurrentUser() == userId) {
- final boolean userHasTrust = getUserHasTrust(userId);
- if (userHasTrust && trustGrantedMessages != null) {
+ if (enabled) {
+ String message = null;
+ if (KeyguardUpdateMonitor.getCurrentUser() == userId
+ && trustGrantedMessages != null) {
+ // Show the first non-empty string provided by a trust agent OR intentionally pass
+ // an empty string through (to prevent the default trust agent string from showing)
for (String msg : trustGrantedMessages) {
message = msg;
if (!TextUtils.isEmpty(message)) {
@@ -483,21 +485,39 @@
}
}
}
- }
- mLogger.logTrustChanged(wasTrusted, enabled, userId);
- if (message != null) {
- mLogger.logShowTrustGrantedMessage(message.toString());
- }
- for (int i = 0; i < mCallbacks.size(); i++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
- if (cb != null) {
- cb.onTrustChanged(userId);
- if (enabled) {
- cb.onTrustGrantedWithFlags(flags, userId, message);
+
+ mLogger.logTrustGrantedWithFlags(flags, userId, message);
+ if (userId == getCurrentUser()) {
+ final TrustGrantFlags trustGrantFlags = new TrustGrantFlags(flags);
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onTrustGrantedForCurrentUser(
+ shouldDismissKeyguardOnTrustGrantedWithCurrentUser(trustGrantFlags),
+ trustGrantFlags, message);
+ }
}
}
}
+ mLogger.logTrustChanged(wasTrusted, enabled, userId);
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onTrustChanged(userId);
+ }
+ }
+ }
+
+ /**
+ * Whether the trust granted call with its passed flags should dismiss keyguard.
+ * It's assumed that the trust was granted for the current user.
+ */
+ private boolean shouldDismissKeyguardOnTrustGrantedWithCurrentUser(TrustGrantFlags flags) {
+ final boolean isBouncerShowing = mPrimaryBouncerIsOrWillBeShowing || mUdfpsBouncerShowing;
+ return (flags.isInitiatedByUser() || flags.dismissKeyguardRequested())
+ && (mDeviceInteractive || flags.temporaryAndRenewable())
+ && (isBouncerShowing || flags.dismissKeyguardRequested());
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index c5142f3..1d58fc9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -19,6 +19,7 @@
import android.telephony.TelephonyManager;
import android.view.WindowManagerPolicyConstants;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settingslib.fuelgauge.BatteryStatus;
@@ -175,11 +176,13 @@
/**
* Called after trust was granted.
- * @param userId of the user that has been granted trust
+ * @param dismissKeyguard whether the keyguard should be dismissed as a result of the
+ * trustGranted
* @param message optional message the trust agent has provided to show that should indicate
* why trust was granted.
*/
- public void onTrustGrantedWithFlags(int flags, int userId, @Nullable String message) { }
+ public void onTrustGrantedForCurrentUser(boolean dismissKeyguard,
+ @NonNull TrustGrantFlags flags, @Nullable String message) { }
/**
* Called when a biometric has been acquired.
diff --git a/packages/SystemUI/src/com/android/keyguard/TrustGrantFlags.java b/packages/SystemUI/src/com/android/keyguard/TrustGrantFlags.java
new file mode 100644
index 0000000..d33732c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/TrustGrantFlags.java
@@ -0,0 +1,98 @@
+/*
+ * 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.keyguard;
+
+import android.service.trust.TrustAgentService;
+
+import java.util.Objects;
+
+/**
+ * Translating {@link android.service.trust.TrustAgentService.GrantTrustFlags} to a more
+ * parsable object. These flags are requested by a TrustAgent.
+ */
+public class TrustGrantFlags {
+ final int mFlags;
+
+ public TrustGrantFlags(int flags) {
+ this.mFlags = flags;
+ }
+
+ /** {@link TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER} */
+ public boolean isInitiatedByUser() {
+ return (mFlags & TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER) != 0;
+ }
+
+ /**
+ * Trust agent is requesting to dismiss the keyguard.
+ * See {@link TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD}.
+ *
+ * This does not guarantee that the keyguard is dismissed.
+ * KeyguardUpdateMonitor makes the final determination whether the keyguard should be dismissed.
+ * {@link KeyguardUpdateMonitorCallback#onTrustGrantedForCurrentUser(
+ * boolean, TrustGrantFlags, String).
+ */
+ public boolean dismissKeyguardRequested() {
+ return (mFlags & TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD) != 0;
+ }
+
+ /** {@link TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE} */
+ public boolean temporaryAndRenewable() {
+ return (mFlags & TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0;
+ }
+
+ /** {@link TrustAgentService.FLAG_GRANT_TRUST_DISPLAY_MESSAGE} */
+ public boolean displayMessage() {
+ return (mFlags & TrustAgentService.FLAG_GRANT_TRUST_DISPLAY_MESSAGE) != 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof TrustGrantFlags)) {
+ return false;
+ }
+
+ return ((TrustGrantFlags) o).mFlags == this.mFlags;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFlags);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ sb.append(mFlags);
+ sb.append("]=");
+
+ if (isInitiatedByUser()) {
+ sb.append("initiatedByUser|");
+ }
+ if (dismissKeyguardRequested()) {
+ sb.append("dismissKeyguard|");
+ }
+ if (temporaryAndRenewable()) {
+ sb.append("temporaryAndRenewable|");
+ }
+ if (displayMessage()) {
+ sb.append("displayMessage|");
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 81b8dfe..6763700 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -25,6 +25,7 @@
import com.android.keyguard.FaceAuthUiEvent
import com.android.keyguard.KeyguardListenModel
import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.keyguard.TrustGrantFlags
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.plugins.log.LogLevel.DEBUG
@@ -368,12 +369,16 @@
}, { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" })
}
- fun logShowTrustGrantedMessage(
+ fun logTrustGrantedWithFlags(
+ flags: Int,
+ userId: Int,
message: String?
) {
logBuffer.log(TAG, DEBUG, {
+ int1 = flags
+ int2 = userId
str1 = message
- }, { "showTrustGrantedMessage message$str1" })
+ }, { "trustGrantedWithFlags[user=$int2] flags=${TrustGrantFlags(int1)} message=$str1" })
}
fun logTrustChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 2101efb..8355c64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -67,6 +67,7 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
@@ -74,6 +75,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.TrustGrantFlags;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.settingslib.Utils;
import com.android.settingslib.fuelgauge.BatteryStatus;
@@ -154,7 +156,8 @@
private final AccessibilityManager mAccessibilityManager;
private final Handler mHandler;
- protected KeyguardIndicationRotateTextViewController mRotateTextViewController;
+ @VisibleForTesting
+ public KeyguardIndicationRotateTextViewController mRotateTextViewController;
private BroadcastReceiver mBroadcastReceiver;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -1188,9 +1191,9 @@
}
@Override
- public void onTrustGrantedWithFlags(int flags, int userId, @Nullable String message) {
- if (!isCurrentUser(userId)) return;
- showTrustGrantedMessage(flags, message);
+ public void onTrustGrantedForCurrentUser(boolean dismissKeyguard,
+ @NonNull TrustGrantFlags flags, @Nullable String message) {
+ showTrustGrantedMessage(dismissKeyguard, message);
}
@Override
@@ -1254,7 +1257,7 @@
return getCurrentUser() == userId;
}
- void showTrustGrantedMessage(int flags, @Nullable CharSequence message) {
+ protected void showTrustGrantedMessage(boolean dismissKeyguard, @Nullable String message) {
mTrustGrantedIndication = message;
updateDeviceEntryIndication(false);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 5514fd0..1ec23e9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -29,6 +29,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
import static com.android.keyguard.FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED;
import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT;
+import static com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser;
import static com.google.common.truth.Truth.assertThat;
@@ -36,6 +37,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
@@ -89,6 +91,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.service.dreams.IDreamManager;
+import android.service.trust.TrustAgentService;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -353,7 +356,9 @@
@After
public void tearDown() {
- mMockitoSession.finishMocking();
+ if (mMockitoSession != null) {
+ mMockitoSession.finishMocking();
+ }
cleanupKeyguardUpdateMonitor();
}
@@ -1316,9 +1321,9 @@
Arrays.asList("Unlocked by wearable"));
// THEN the showTrustGrantedMessage should be called with the first message
- verify(mTestCallback).onTrustGrantedWithFlags(
- eq(0),
- eq(KeyguardUpdateMonitor.getCurrentUser()),
+ verify(mTestCallback).onTrustGrantedForCurrentUser(
+ anyBoolean(),
+ eq(new TrustGrantFlags(0)),
eq("Unlocked by wearable"));
}
@@ -1729,6 +1734,155 @@
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
}
+
+ @Test
+ public void testOnTrustGrantedForCurrentUser_dismissKeyguardRequested_deviceInteractive() {
+ // GIVEN device is interactive
+ deviceIsInteractive();
+
+ // GIVEN callback is registered
+ KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(callback);
+
+ // WHEN onTrustChanged with TRUST_DISMISS_KEYGUARD flag
+ mKeyguardUpdateMonitor.onTrustChanged(
+ true /* enabled */,
+ getCurrentUser() /* userId */,
+ TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD /* flags */,
+ null /* trustGrantedMessages */);
+
+ // THEN onTrustGrantedForCurrentUser callback called
+ verify(callback).onTrustGrantedForCurrentUser(
+ eq(true) /* dismissKeyguard */,
+ eq(new TrustGrantFlags(TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD)),
+ eq(null) /* message */
+ );
+ }
+
+ @Test
+ public void testOnTrustGrantedForCurrentUser_dismissKeyguardRequested_doesNotDismiss() {
+ // GIVEN device is NOT interactive
+
+ // GIVEN callback is registered
+ KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(callback);
+
+ // WHEN onTrustChanged with TRUST_DISMISS_KEYGUARD flag
+ mKeyguardUpdateMonitor.onTrustChanged(
+ true /* enabled */,
+ getCurrentUser() /* userId */,
+ TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD /* flags */,
+ null /* trustGrantedMessages */);
+
+ // THEN onTrustGrantedForCurrentUser callback called
+ verify(callback).onTrustGrantedForCurrentUser(
+ eq(false) /* dismissKeyguard */,
+ eq(new TrustGrantFlags(TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD)),
+ eq(null) /* message */
+ );
+ }
+
+ @Test
+ public void testOnTrustGrantedForCurrentUser_dismissKeyguardRequested_temporaryAndRenewable() {
+ // GIVEN device is interactive
+ deviceIsInteractive();
+
+ // GIVEN callback is registered
+ KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(callback);
+
+ // WHEN onTrustChanged for a different user
+ mKeyguardUpdateMonitor.onTrustChanged(
+ true /* enabled */,
+ 546 /* userId, not the current userId */,
+ 0 /* flags */,
+ null /* trustGrantedMessages */);
+
+ // THEN onTrustGrantedForCurrentUser callback called
+ verify(callback, never()).onTrustGrantedForCurrentUser(
+ anyBoolean() /* dismissKeyguard */,
+ anyObject() /* flags */,
+ anyString() /* message */
+ );
+ }
+
+ @Test
+ public void testOnTrustGranted_differentUser_noCallback() {
+ // GIVEN device is interactive
+
+ // GIVEN callback is registered
+ KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(callback);
+
+ // WHEN onTrustChanged with TRUST_DISMISS_KEYGUARD AND TRUST_TEMPORARY_AND_RENEWABLE
+ // flags (temporary & rewable is active unlock)
+ mKeyguardUpdateMonitor.onTrustChanged(
+ true /* enabled */,
+ getCurrentUser() /* userId */,
+ TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD
+ | TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE /* flags */,
+ null /* trustGrantedMessages */);
+
+ // THEN onTrustGrantedForCurrentUser callback called
+ verify(callback).onTrustGrantedForCurrentUser(
+ eq(true) /* dismissKeyguard */,
+ eq(new TrustGrantFlags(TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD
+ | TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)),
+ eq(null) /* message */
+ );
+ }
+
+ @Test
+ public void testOnTrustGrantedForCurrentUser_bouncerShowing_initiatedByUser() {
+ // GIVEN device is interactive & bouncer is showing
+ deviceIsInteractive();
+ bouncerFullyVisible();
+
+ // GIVEN callback is registered
+ KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(callback);
+
+ // WHEN onTrustChanged with INITIATED_BY_USER flag
+ mKeyguardUpdateMonitor.onTrustChanged(
+ true /* enabled */,
+ getCurrentUser() /* userId, not the current userId */,
+ TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER /* flags */,
+ null /* trustGrantedMessages */);
+
+ // THEN onTrustGrantedForCurrentUser callback called
+ verify(callback, never()).onTrustGrantedForCurrentUser(
+ eq(true) /* dismissKeyguard */,
+ eq(new TrustGrantFlags(TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER)),
+ anyString() /* message */
+ );
+ }
+
+ @Test
+ public void testOnTrustGrantedForCurrentUser_bouncerShowing_temporaryRenewable() {
+ // GIVEN device is NOT interactive & bouncer is showing
+ bouncerFullyVisible();
+
+ // GIVEN callback is registered
+ KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(callback);
+
+ // WHEN onTrustChanged with INITIATED_BY_USER flag
+ mKeyguardUpdateMonitor.onTrustChanged(
+ true /* enabled */,
+ getCurrentUser() /* userId, not the current userId */,
+ TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER
+ | TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE /* flags */,
+ null /* trustGrantedMessages */);
+
+ // THEN onTrustGrantedForCurrentUser callback called
+ verify(callback, never()).onTrustGrantedForCurrentUser(
+ eq(true) /* dismissKeyguard */,
+ eq(new TrustGrantFlags(TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER
+ | TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)),
+ anyString() /* message */
+ );
+ }
+
private void cleanupKeyguardUpdateMonitor() {
if (mKeyguardUpdateMonitor != null) {
mKeyguardUpdateMonitor.removeCallback(mTestCallback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index e8a7ec8..ab7c52e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -87,6 +87,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.TrustGrantFlags;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.R;
@@ -1068,7 +1069,8 @@
// GIVEN a trust granted message but trust isn't granted
final String trustGrantedMsg = "testing trust granted message";
- mController.getKeyguardCallback().onTrustGrantedWithFlags(0, 0, trustGrantedMsg);
+ mController.getKeyguardCallback().onTrustGrantedForCurrentUser(
+ false, new TrustGrantFlags(0), trustGrantedMsg);
verifyHideIndication(INDICATION_TYPE_TRUST);
@@ -1092,7 +1094,8 @@
// WHEN the showTrustGranted method is called
final String trustGrantedMsg = "testing trust granted message";
- mController.getKeyguardCallback().onTrustGrantedWithFlags(0, 0, trustGrantedMsg);
+ mController.getKeyguardCallback().onTrustGrantedForCurrentUser(
+ false, new TrustGrantFlags(0), trustGrantedMsg);
// THEN verify the trust granted message shows
verifyIndicationMessage(
@@ -1109,7 +1112,8 @@
when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
// WHEN the showTrustGranted method is called with a null message
- mController.getKeyguardCallback().onTrustGrantedWithFlags(0, 0, null);
+ mController.getKeyguardCallback().onTrustGrantedForCurrentUser(
+ false, new TrustGrantFlags(0), null);
// THEN verify the default trust granted message shows
verifyIndicationMessage(
@@ -1126,7 +1130,8 @@
when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
// WHEN the showTrustGranted method is called with an EMPTY string
- mController.getKeyguardCallback().onTrustGrantedWithFlags(0, 0, "");
+ mController.getKeyguardCallback().onTrustGrantedForCurrentUser(
+ false, new TrustGrantFlags(0), "");
// THEN verify NO trust message is shown
verifyNoMessage(INDICATION_TYPE_TRUST);
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index be21075..fbde9e0 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -227,6 +227,12 @@
return mParams.getName();
}
+ /** Returns the policy specified for this policy type */
+ public @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
+ @VirtualDeviceParams.PolicyType int policyType) {
+ return mParams.getDevicePolicy(policyType);
+ }
+
/** Returns the unique device ID of this device. */
@Override // Binder call
public int getDeviceId() {
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index c400a74..a8797a0 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -233,6 +233,13 @@
mLocalService.onAppsOnVirtualDeviceChanged();
}
+ @VisibleForTesting
+ void addVirtualDevice(VirtualDeviceImpl virtualDevice) {
+ synchronized (mVirtualDeviceManagerLock) {
+ mVirtualDevices.put(virtualDevice.getAssociationId(), virtualDevice);
+ }
+ }
+
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub implements
VirtualDeviceImpl.PendingTrampolineCallback {
@@ -358,6 +365,12 @@
return virtualDevices;
}
+ @Override // BinderCall
+ @VirtualDeviceParams.DevicePolicy
+ public int getDevicePolicy(int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
+ return mLocalService.getDevicePolicy(deviceId, policyType);
+ }
+
@Nullable
private AssociationInfo getAssociationInfo(String packageName, int associationId) {
final int callingUserId = getCallingUserHandle().getIdentifier();
@@ -439,6 +452,20 @@
}
@Override
+ @VirtualDeviceParams.DevicePolicy
+ public int getDevicePolicy(int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
+ synchronized (mVirtualDeviceManagerLock) {
+ for (int i = 0; i < mVirtualDevices.size(); i++) {
+ final VirtualDeviceImpl device = mVirtualDevices.valueAt(i);
+ if (device.getDeviceId() == deviceId) {
+ return device.getDevicePolicy(policyType);
+ }
+ }
+ }
+ return VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
+ }
+
+ @Override
public void onVirtualDisplayCreated(int displayId) {
final VirtualDisplayListener[] listeners;
synchronized (mVirtualDeviceManagerLock) {
diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index 81b56a3..d2e572f 100644
--- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.companion.virtual.IVirtualDevice;
+import android.companion.virtual.VirtualDeviceParams;
import java.util.Set;
@@ -109,4 +110,14 @@
* Returns true if the {@code displayId} is owned by any virtual device
*/
public abstract boolean isDisplayOwnedByAnyVirtualDevice(int displayId);
+
+ /**
+ * Returns the device policy for the given virtual device and policy type.
+ *
+ * <p>In case the virtual device identifier is not valid, or there's no explicitly specified
+ * policy for that device and policy type, then
+ * {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT} is returned.
+ */
+ public abstract @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
+ int deviceId, @VirtualDeviceParams.PolicyType int policyType);
}
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index 4c18d0b..56edde0 100644
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -57,7 +57,6 @@
import android.view.WindowInsets.Type;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.Button;
@@ -109,18 +108,13 @@
mContext = display.getDisplayId() == DEFAULT_DISPLAY
? uiContext : uiContext.createDisplayContext(display);
mHandler = new H(looper);
- mShowDelayMs = getNavBarExitDuration() * 3;
+ mShowDelayMs = context.getResources().getInteger(R.integer.dock_enter_exit_duration) * 3L;
mPanicThresholdMs = context.getResources()
.getInteger(R.integer.config_immersive_mode_confirmation_panic);
mVrModeEnabled = vrModeEnabled;
mCanSystemBarsBeShownByUser = canSystemBarsBeShownByUser;
}
- private long getNavBarExitDuration() {
- Animation exit = AnimationUtils.loadAnimation(mContext, R.anim.dock_bottom_exit);
- return exit != null ? exit.getDuration() : 0;
- }
-
static boolean loadSetting(int currentUserId, Context context) {
final boolean wasConfirmed = sConfirmed;
sConfirmed = false;
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 5fda3d6..c715a21 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -16,6 +16,9 @@
package com.android.server.companion.virtual;
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
import static com.google.common.truth.Truth.assertThat;
@@ -44,6 +47,7 @@
import android.app.admin.DevicePolicyManager;
import android.companion.AssociationInfo;
import android.companion.virtual.IVirtualDeviceActivityListener;
+import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.audio.IAudioConfigChangedCallback;
import android.companion.virtual.audio.IAudioRoutingCallback;
@@ -240,6 +244,55 @@
mAssociationInfo, new Binder(), /* ownerUid */ 0, /* uniqueId */ 1,
mInputController, (int associationId) -> {}, mPendingTrampolineCallback,
mActivityListener, mRunningAppsChangedCallback, params);
+ mVdms.addVirtualDevice(mDeviceImpl);
+ }
+
+ @Test
+ public void getDevicePolicy_invalidDeviceId_returnsDefault() {
+ assertThat(
+ mLocalService.getDevicePolicy(
+ VirtualDeviceManager.INVALID_DEVICE_ID, POLICY_TYPE_SENSORS))
+ .isEqualTo(DEVICE_POLICY_DEFAULT);
+ }
+
+ @Test
+ public void getDevicePolicy_defaultDeviceId_returnsDefault() {
+ assertThat(
+ mLocalService.getDevicePolicy(
+ VirtualDeviceManager.DEFAULT_DEVICE_ID, POLICY_TYPE_SENSORS))
+ .isEqualTo(DEVICE_POLICY_DEFAULT);
+ }
+
+ @Test
+ public void getDevicePolicy_nonExistentDeviceId_returnsDefault() {
+ assertThat(
+ mLocalService.getDevicePolicy(mDeviceImpl.getDeviceId() + 1, POLICY_TYPE_SENSORS))
+ .isEqualTo(DEVICE_POLICY_DEFAULT);
+ }
+
+ @Test
+ public void getDevicePolicy_unspecifiedPolicy_returnsDefault() {
+ assertThat(
+ mLocalService.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
+ .isEqualTo(DEVICE_POLICY_DEFAULT);
+ }
+
+ @Test
+ public void getDevicePolicy_returnsCustom() {
+ VirtualDeviceParams params = new VirtualDeviceParams
+ .Builder()
+ .setBlockedActivities(getBlockedActivities())
+ .addDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
+ .build();
+ mDeviceImpl = new VirtualDeviceImpl(mContext,
+ mAssociationInfo, new Binder(), /* ownerUid */ 0, /* uniqueId */ 1,
+ mInputController, (int associationId) -> {}, mPendingTrampolineCallback,
+ mActivityListener, mRunningAppsChangedCallback, params);
+ mVdms.addVirtualDevice(mDeviceImpl);
+
+ assertThat(
+ mLocalService.getDevicePolicy(mDeviceImpl.getDeviceId(), POLICY_TYPE_SENSORS))
+ .isEqualTo(DEVICE_POLICY_CUSTOM);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java
index 77f1e24..036b6df 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java
@@ -37,6 +37,8 @@
VirtualDeviceParams originalParams = new VirtualDeviceParams.Builder()
.setLockState(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED)
.setUsersWithMatchingAccounts(Set.of(UserHandle.of(123), UserHandle.of(456)))
+ .addDevicePolicy(VirtualDeviceParams.POLICY_TYPE_SENSORS,
+ VirtualDeviceParams.DEVICE_POLICY_CUSTOM)
.build();
Parcel parcel = Parcel.obtain();
originalParams.writeToParcel(parcel, 0);
@@ -47,5 +49,7 @@
assertThat(params.getLockState()).isEqualTo(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED);
assertThat(params.getUsersWithMatchingAccounts())
.containsExactly(UserHandle.of(123), UserHandle.of(456));
+ assertThat(params.getDevicePolicy(VirtualDeviceParams.POLICY_TYPE_SENSORS))
+ .isEqualTo(VirtualDeviceParams.DEVICE_POLICY_CUSTOM);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
index 846a506..5e1fae0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
@@ -192,16 +192,17 @@
}
private static class SyncTarget implements SurfaceSyncGroup.SyncTarget {
- private SurfaceSyncGroup.SyncBufferCallback mSyncBufferCallback;
+ private SurfaceSyncGroup.TransactionReadyCallback mTransactionReadyCallback;
@Override
- public void onReadyToSync(SurfaceSyncGroup.SyncBufferCallback syncBufferCallback) {
- mSyncBufferCallback = syncBufferCallback;
+ public void onAddedToSyncGroup(SurfaceSyncGroup parentSyncGroup,
+ SurfaceSyncGroup.TransactionReadyCallback transactionReadyCallback) {
+ mTransactionReadyCallback = transactionReadyCallback;
}
void onBufferReady() {
SurfaceControl.Transaction t = new StubTransaction();
- mSyncBufferCallback.onBufferReady(t);
+ mTransactionReadyCallback.onTransactionReady(t);
}
}
}