Merge "Ensure VcnGatewayConnection#isQuitting never gets unset after being set" into sc-dev
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 95712cd..262dc83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -132,7 +132,7 @@
if (!row.isPinned()) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
}
- mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
+ mStatusBarKeyguardViewManager.showGenericBouncer(true /* scrimmed */);
mPendingRemoteInputView = clicked;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 9a5e948..1fc1473 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -26,6 +26,7 @@
import android.content.Intent;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -37,6 +38,7 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -94,4 +96,11 @@
verify(mRemoteInputCallback, times(1)).onWorkChallengeChanged();
}
+ @Test
+ public void testShowGenericBouncer_onLockedRemoteInput() {
+ mRemoteInputCallback.onLockedRemoteInput(
+ mock(ExpandableNotificationRow.class), mock(View.class));
+
+ verify(mStatusBarKeyguardViewManager).showGenericBouncer(true);
+ }
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 867c093..b068f86 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -24,6 +24,7 @@
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+import static android.telephony.SubscriptionManager.isValidSubscriptionId;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -435,6 +436,15 @@
}
}
+ private boolean isActiveSubGroup(
+ @NonNull ParcelUuid subGrp, @NonNull TelephonySubscriptionSnapshot snapshot) {
+ if (subGrp == null || snapshot == null) {
+ return false;
+ }
+
+ return Objects.equals(subGrp, snapshot.getActiveDataSubscriptionGroup());
+ }
+
private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback {
/**
* Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker}
@@ -452,28 +462,49 @@
// Start any VCN instances as necessary
for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
+ final ParcelUuid subGrp = entry.getKey();
+
+ // TODO(b/193687515): Support multiple VCNs active at the same time
if (snapshot.packageHasPermissionsForSubscriptionGroup(
- entry.getKey(), entry.getValue().getProvisioningPackageName())) {
- if (!mVcns.containsKey(entry.getKey())) {
- startVcnLocked(entry.getKey(), entry.getValue());
+ subGrp, entry.getValue().getProvisioningPackageName())
+ && isActiveSubGroup(subGrp, snapshot)) {
+ if (!mVcns.containsKey(subGrp)) {
+ startVcnLocked(subGrp, entry.getValue());
}
// Cancel any scheduled teardowns for active subscriptions
- mHandler.removeCallbacksAndMessages(mVcns.get(entry.getKey()));
+ mHandler.removeCallbacksAndMessages(mVcns.get(subGrp));
}
}
// Schedule teardown of any VCN instances that have lost carrier privileges (after a
// delay)
for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) {
- final VcnConfig config = mConfigs.get(entry.getKey());
+ final ParcelUuid subGrp = entry.getKey();
+ final VcnConfig config = mConfigs.get(subGrp);
+ final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot);
+ final boolean isValidActiveDataSubIdNotInVcnSubGrp =
+ isValidSubscriptionId(snapshot.getActiveDataSubscriptionId())
+ && !isActiveSubGroup(subGrp, snapshot);
+
+ // TODO(b/193687515): Support multiple VCNs active at the same time
if (config == null
|| !snapshot.packageHasPermissionsForSubscriptionGroup(
- entry.getKey(), config.getProvisioningPackageName())) {
- final ParcelUuid uuidToTeardown = entry.getKey();
+ subGrp, config.getProvisioningPackageName())
+ || !isActiveSubGrp) {
+ final ParcelUuid uuidToTeardown = subGrp;
final Vcn instanceToTeardown = entry.getValue();
+ // TODO(b/193687515): Support multiple VCNs active at the same time
+ // If directly switching to a subscription not in the current group,
+ // teardown immediately to prevent other subscription's network from being
+ // outscored by the VCN. Otherwise, teardown after a delay to ensure that
+ // SIM profile switches do not trigger the VCN to cycle.
+ final long teardownDelayMs =
+ isValidActiveDataSubIdNotInVcnSubGrp
+ ? 0
+ : CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS;
mHandler.postDelayed(() -> {
synchronized (mLock) {
// Guard against case where this is run after a old instance was
@@ -489,7 +520,7 @@
uuidToTeardown, VCN_STATUS_CODE_INACTIVE);
}
}
- }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+ }, instanceToTeardown, teardownDelayMs);
} else {
// If this VCN's status has not changed, update it with the new snapshot
entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);
@@ -555,8 +586,13 @@
private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
logDbg("Starting VCN config for subGrp: " + subscriptionGroup);
- // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active
- // VCN.
+ // TODO(b/193687515): Support multiple VCNs active at the same time
+ if (!mVcns.isEmpty()) {
+ // Only one VCN supported at a time; teardown all others before starting new one
+ for (ParcelUuid uuidToTeardown : mVcns.keySet()) {
+ stopVcnLocked(uuidToTeardown);
+ }
+ }
final VcnCallbackImpl vcnCallback = new VcnCallbackImpl(subscriptionGroup);
@@ -584,7 +620,10 @@
final Vcn vcn = mVcns.get(subscriptionGroup);
vcn.updateConfig(config);
} else {
- startVcnLocked(subscriptionGroup, config);
+ // TODO(b/193687515): Support multiple VCNs active at the same time
+ if (isActiveSubGroup(subscriptionGroup, mLastSnapshot)) {
+ startVcnLocked(subscriptionGroup, config);
+ }
}
}
@@ -1009,6 +1048,11 @@
}
}
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setLastSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) {
+ mLastSnapshot = Objects.requireNonNull(snapshot);
+ }
+
private void logVdbg(String msg) {
if (VDBG) {
Slog.v(TAG, msg);
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 9d1c838..9079ba8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -50,7 +50,7 @@
static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
static final boolean DEBUG_BROADCAST_DEFERRAL = DEBUG_BROADCAST || false;
static final boolean DEBUG_COMPACTION = DEBUG_ALL || false;
- static final boolean DEBUG_FREEZER = DEBUG_ALL || true;
+ static final boolean DEBUG_FREEZER = DEBUG_ALL || false;
static final boolean DEBUG_LRU = DEBUG_ALL || false;
static final boolean DEBUG_MU = DEBUG_ALL || false;
static final boolean DEBUG_NETWORK = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 8db7eea..9dbb707 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -992,9 +992,7 @@
}
if (!opt.isFrozen()) {
- if (DEBUG_FREEZER) {
- Slog.d(TAG_AM, "sync unfroze " + pid + " " + app.processName);
- }
+ Slog.d(TAG_AM, "sync unfroze " + pid + " " + app.processName);
mFreezeHandler.sendMessage(
mFreezeHandler.obtainMessage(REPORT_UNFREEZE_MSG,
@@ -1386,9 +1384,7 @@
return;
}
- if (DEBUG_FREEZER) {
- Slog.d(TAG_AM, "froze " + pid + " " + name);
- }
+ Slog.d(TAG_AM, "froze " + pid + " " + name);
EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 012e47e..183fabd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -215,9 +215,9 @@
}
@Override // Binder call
- public void enroll(final IBinder token, final byte[] hardwareAuthToken, final int userId,
- final IFingerprintServiceReceiver receiver, final String opPackageName,
- @FingerprintManager.EnrollReason int enrollReason) {
+ public void enroll(final IBinder token, @NonNull final byte[] hardwareAuthToken,
+ final int userId, final IFingerprintServiceReceiver receiver,
+ final String opPackageName, @FingerprintManager.EnrollReason int enrollReason) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 3a214f4..706ac10 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -85,9 +85,12 @@
void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token,
@NonNull String opPackageName, long challenge);
- void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken, int userId,
- @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
- @FingerprintManager.EnrollReason int enrollReason,
+ /**
+ * Schedules fingerprint enrollment.
+ */
+ void scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken,
+ int userId, @NonNull IFingerprintServiceReceiver receiver,
+ @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason,
@NonNull FingerprintStateCallback fingerprintStateCallback);
void cancelEnrollment(int sensorId, @NonNull IBinder token);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index cfc4674..102b074 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -329,9 +329,10 @@
}
@Override
- public void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken,
- int userId, @NonNull IFingerprintServiceReceiver receiver,
- @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason,
+ public void scheduleEnroll(int sensorId, @NonNull IBinder token,
+ @NonNull byte[] hardwareAuthToken, int userId,
+ @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
+ @FingerprintManager.EnrollReason int enrollReason,
@NonNull FingerprintStateCallback fingerprintStateCallback) {
mHandler.post(() -> {
final int maxTemplatesPerUser = mSensors.get(sensorId).getSensorProperties()
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 0bec09c..c0b8648 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2174,6 +2174,7 @@
@Override
public VerifyCredentialResponse verifyGatekeeperPasswordHandle(long gatekeeperPasswordHandle,
long challenge, int userId) {
+
checkPasswordReadPermission();
final VerifyCredentialResponse response;
@@ -2185,6 +2186,7 @@
synchronized (mSpManager) {
if (gatekeeperPassword == null) {
+ Slog.d(TAG, "No gatekeeper password for handle");
response = VerifyCredentialResponse.ERROR;
} else {
response = mSpManager.verifyChallengeInternal(getGateKeeperService(),
diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
index f13f406..5442e5b 100644
--- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
@@ -256,8 +256,8 @@
private boolean componentMapsToRecognitionService(@NonNull ComponentName serviceComponent) {
List<ResolveInfo> resolveInfos =
- getContext().getPackageManager().queryIntentServices(
- new Intent(RecognitionService.SERVICE_INTERFACE), 0);
+ getContext().getPackageManager().queryIntentServicesAsUser(
+ new Intent(RecognitionService.SERVICE_INTERFACE), 0, getUserId());
if (resolveInfos == null) {
return false;
}
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index fca706b..a31c56a 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -36,6 +36,7 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -85,6 +86,8 @@
@NonNull private final SubscriptionManager mSubscriptionManager;
@NonNull private final CarrierConfigManager mCarrierConfigManager;
+ @NonNull private final ActiveDataSubscriptionIdListener mActiveDataSubIdListener;
+
// TODO (Android T+): Add ability to handle multiple subIds per slot.
@NonNull private final Map<Integer, Integer> mReadySubIdsBySlotId = new HashMap<>();
@NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener;
@@ -112,6 +115,7 @@
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
+ mActiveDataSubIdListener = new ActiveDataSubscriptionIdListener();
mSubscriptionChangedListener =
new OnSubscriptionsChangedListener() {
@@ -124,16 +128,20 @@
/** Registers the receivers, and starts tracking subscriptions. */
public void register() {
+ final HandlerExecutor executor = new HandlerExecutor(mHandler);
+
mContext.registerReceiver(
this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler);
mSubscriptionManager.addOnSubscriptionsChangedListener(
- new HandlerExecutor(mHandler), mSubscriptionChangedListener);
+ executor, mSubscriptionChangedListener);
+ mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener);
}
/** Unregisters the receivers, and stops tracking subscriptions. */
public void unregister() {
mContext.unregisterReceiver(this);
mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener);
+ mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener);
}
/**
@@ -185,7 +193,8 @@
}
final TelephonySubscriptionSnapshot newSnapshot =
- new TelephonySubscriptionSnapshot(newSubIdToInfoMap, privilegedPackages);
+ new TelephonySubscriptionSnapshot(
+ mDeps.getActiveDataSubscriptionId(), newSubIdToInfoMap, privilegedPackages);
// If snapshot was meaningfully updated, fire the callback
if (!newSnapshot.equals(mCurrentSnapshot)) {
@@ -242,16 +251,20 @@
/** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */
public static class TelephonySubscriptionSnapshot {
+ private final int mActiveDataSubId;
private final Map<Integer, SubscriptionInfo> mSubIdToInfoMap;
private final Map<ParcelUuid, Set<String>> mPrivilegedPackages;
public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT =
- new TelephonySubscriptionSnapshot(Collections.emptyMap(), Collections.emptyMap());
+ new TelephonySubscriptionSnapshot(
+ INVALID_SUBSCRIPTION_ID, Collections.emptyMap(), Collections.emptyMap());
@VisibleForTesting(visibility = Visibility.PRIVATE)
TelephonySubscriptionSnapshot(
+ int activeDataSubId,
@NonNull Map<Integer, SubscriptionInfo> subIdToInfoMap,
@NonNull Map<ParcelUuid, Set<String>> privilegedPackages) {
+ mActiveDataSubId = activeDataSubId;
Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null");
Objects.requireNonNull(privilegedPackages, "privilegedPackages was null");
@@ -265,6 +278,22 @@
mPrivilegedPackages = Collections.unmodifiableMap(unmodifiableInnerSets);
}
+ /** Returns the active subscription ID. May be INVALID_SUBSCRIPTION_ID */
+ public int getActiveDataSubscriptionId() {
+ return mActiveDataSubId;
+ }
+
+ /** Returns the active subscription group */
+ @Nullable
+ public ParcelUuid getActiveDataSubscriptionGroup() {
+ final SubscriptionInfo info = mSubIdToInfoMap.get(getActiveDataSubscriptionId());
+ if (info == null) {
+ return null;
+ }
+
+ return info.getGroupUuid();
+ }
+
/** Returns the active subscription groups */
@NonNull
public Set<ParcelUuid> getActiveSubscriptionGroups() {
@@ -313,7 +342,7 @@
@Override
public int hashCode() {
- return Objects.hash(mSubIdToInfoMap, mPrivilegedPackages);
+ return Objects.hash(mActiveDataSubId, mSubIdToInfoMap, mPrivilegedPackages);
}
@Override
@@ -324,7 +353,8 @@
final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj;
- return mSubIdToInfoMap.equals(other.mSubIdToInfoMap)
+ return mActiveDataSubId == other.mActiveDataSubId
+ && mSubIdToInfoMap.equals(other.mSubIdToInfoMap)
&& mPrivilegedPackages.equals(other.mPrivilegedPackages);
}
@@ -333,6 +363,7 @@
pw.println("TelephonySubscriptionSnapshot:");
pw.increaseIndent();
+ pw.println("mActiveDataSubId: " + mActiveDataSubId);
pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap);
pw.println("mPrivilegedPackages: " + mPrivilegedPackages);
@@ -342,7 +373,8 @@
@Override
public String toString() {
return "TelephonySubscriptionSnapshot{ "
- + "mSubIdToInfoMap=" + mSubIdToInfoMap
+ + "mActiveDataSubId=" + mActiveDataSubId
+ + ", mSubIdToInfoMap=" + mSubIdToInfoMap
+ ", mPrivilegedPackages=" + mPrivilegedPackages
+ " }";
}
@@ -362,6 +394,14 @@
void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot);
}
+ private class ActiveDataSubscriptionIdListener extends TelephonyCallback
+ implements TelephonyCallback.ActiveDataSubscriptionIdListener {
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ handleSubscriptionsChanged();
+ }
+ }
+
/** External static dependencies for test injection */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class Dependencies {
@@ -369,5 +409,10 @@
public boolean isConfigForIdentifiedCarrier(PersistableBundle bundle) {
return CarrierConfigManager.isConfigForIdentifiedCarrier(bundle);
}
+
+ /** Gets the active Subscription ID */
+ public int getActiveDataSubscriptionId() {
+ return SubscriptionManager.getActiveDataSubscriptionId();
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4468252..4c1992e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4725,7 +4725,8 @@
*/
private void postApplyAnimation(boolean visible) {
final boolean delayed = isAnimating(PARENTS | CHILDREN,
- ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION);
+ ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION
+ | ANIMATION_TYPE_RECENTS);
if (!delayed) {
// We aren't delayed anything, but exiting windows rely on the animation finished
// callback being called in case the ActivityRecord was pretending to be delayed,
@@ -4745,7 +4746,8 @@
// updated.
// If we're becoming invisible, update the client visibility if we are not running an
// animation. Otherwise, we'll update client visibility in onAnimationFinished.
- if (visible || !isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) {
+ if (visible || !isAnimating(PARENTS,
+ ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)) {
setClientVisible(visible);
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index a10b5d6..b1bdc11 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -239,8 +239,10 @@
// Fetch all the surface controls and pass them to the client to get the animation
// started. Cancel any existing recents animation running synchronously (do not hold the
// WM lock)
- mWindowManager.cancelRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION,
- "startRecentsActivity");
+ if (mWindowManager.getRecentsAnimationController() != null) {
+ mWindowManager.getRecentsAnimationController().forceCancelAnimation(
+ REORDER_MOVE_TO_ORIGINAL_POSITION, "startRecentsActivity");
+ }
mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner,
this, mDefaultTaskDisplayArea.getDisplayId(),
mTaskSupervisor.mRecentTasks.getRecentTaskIds(), targetActivity);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 9e147b1..e346e3e 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -122,9 +122,7 @@
new ArrayList<>();
private final int mDisplayId;
private boolean mWillFinishToHome = false;
- private final Runnable mFailsafeRunnable = () -> cancelAnimation(
- mWillFinishToHome ? REORDER_MOVE_TO_TOP : REORDER_MOVE_TO_ORIGINAL_POSITION,
- "failSafeRunnable");
+ private final Runnable mFailsafeRunnable = this::onFailsafe;
// The recents component app token that is shown behind the visibile tasks
private ActivityRecord mTargetActivityRecord;
@@ -262,9 +260,6 @@
final long token = Binder.clearCallingIdentity();
try {
synchronized (mService.getWindowManagerLock()) {
- if (mCanceled) {
- return;
- }
// Remove all new task targets.
for (int i = mPendingNewTaskTargets.size() - 1; i >= 0; i--) {
removeTaskInternal(mPendingNewTaskTargets.get(i));
@@ -807,6 +802,14 @@
}, mPendingWallpaperAnimations);
}
+ void forceCancelAnimation(@ReorderMode int reorderMode, String reason) {
+ if (!mCanceled) {
+ cancelAnimation(reorderMode, reason);
+ } else {
+ continueDeferredCancelAnimation();
+ }
+ }
+
void cancelAnimation(@ReorderMode int reorderMode, String reason) {
cancelAnimation(reorderMode, false /*screenshot */, reason);
}
@@ -821,9 +824,6 @@
* finish the animation.
*/
public void cancelAnimationForHomeStart() {
- if (mCanceled) {
- return;
- }
final int reorderMode = mTargetActivityType == ACTIVITY_TYPE_HOME && mWillFinishToHome
? REORDER_MOVE_TO_TOP
: REORDER_KEEP_IN_PLACE;
@@ -836,9 +836,6 @@
* how to finish the animation.
*/
public void cancelAnimationForDisplayChange() {
- if (mCanceled) {
- return;
- }
cancelAnimation(mWillFinishToHome ? REORDER_MOVE_TO_TOP : REORDER_MOVE_TO_ORIGINAL_POSITION,
true /* screenshot */, "cancelAnimationForDisplayChange");
}
@@ -868,6 +865,8 @@
if (taskSnapshot != null) {
// Defer until the runner calls back to cleanupScreenshot()
adapter.setSnapshotOverlay(taskSnapshot);
+ // Schedule a new failsafe for if the runner doesn't clean up the screenshot
+ scheduleFailsafe();
} else {
// Do a normal cancel since we couldn't screenshot
mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
@@ -1014,6 +1013,12 @@
mService.mH.postDelayed(mFailsafeRunnable, FAILSAFE_DELAY);
}
+ void onFailsafe() {
+ forceCancelAnimation(
+ mWillFinishToHome ? REORDER_MOVE_TO_TOP : REORDER_MOVE_TO_ORIGINAL_POSITION,
+ "onFailsafe");
+ }
+
private void linkToDeathOfRunner() throws RemoteException {
if (!mLinkedToDeathOfRunner) {
mRunner.asBinder().linkToDeath(this, 0);
@@ -1030,13 +1035,7 @@
@Override
public void binderDied() {
- if (!mCanceled) {
- cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
- } else {
- // If we are already canceled but with a screenshot, and are waiting for the
- // cleanupScreenshot() callback, then force-finish the animation now
- continueDeferredCancelAnimation();
- }
+ forceCancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
synchronized (mService.getWindowManagerLock()) {
// Clear associated input consumers on runner death
@@ -1358,5 +1357,7 @@
+ mCancelOnNextTransitionStart);
pw.print(innerPrefix); pw.println("mCancelDeferredWithScreenshot="
+ mCancelDeferredWithScreenshot);
+ pw.print(innerPrefix); pw.println("mPendingCancelWithScreenshotReorderMode="
+ + mPendingCancelWithScreenshotReorderMode);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 6be47e1..cbcbf52 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -126,6 +126,9 @@
final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) {
+ Slog.d(TAG, "onServiceConnected to " + name + " for user(" + mUser + ")");
+ }
synchronized (mServiceStub) {
mService = IVoiceInteractionService.Stub.asInterface(service);
try {
@@ -137,7 +140,13 @@
@Override
public void onServiceDisconnected(ComponentName name) {
- mService = null;
+ if (DEBUG) {
+ Slog.d(TAG, "onServiceDisconnected to " + name);
+ }
+ synchronized (mServiceStub) {
+ mService = null;
+ resetHotwordDetectionConnectionLocked();
+ }
}
};
@@ -575,6 +584,20 @@
mHotwordDetectionConnection.forceRestart();
}
+ void resetHotwordDetectionConnectionLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "resetHotwordDetectionConnectionLocked");
+ }
+ if (mHotwordDetectionConnection == null) {
+ if (DEBUG) {
+ Slog.w(TAG, "reset, but no hotword detection connection");
+ }
+ return;
+ }
+ mHotwordDetectionConnection.cancelLocked();
+ mHotwordDetectionConnection = null;
+ }
+
public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!mValid) {
pw.print(" NOT VALID: ");
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index b7a6d0f..7c7dc4d 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -23,6 +23,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
@@ -50,6 +51,7 @@
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.annotation.NonNull;
@@ -99,6 +101,7 @@
import org.mockito.ArgumentCaptor;
import java.io.FileNotFoundException;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -227,6 +230,7 @@
setupMockedCarrierPrivilege(true);
mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
+ setupActiveSubscription(TEST_UUID_1);
doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
doReturn(mMockIBinder).when(mMockStatusCallback).asBinder();
@@ -300,23 +304,65 @@
}
private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
- Set<ParcelUuid> activeSubscriptionGroups) {
+ ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups) {
return triggerSubscriptionTrackerCbAndGetSnapshot(
- activeSubscriptionGroups, Collections.emptyMap());
+ activeDataSubGrp, activeSubscriptionGroups, Collections.emptyMap());
}
private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
- Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap) {
+ ParcelUuid activeDataSubGrp,
+ Set<ParcelUuid> activeSubscriptionGroups,
+ Map<Integer, ParcelUuid> subIdToGroupMap) {
return triggerSubscriptionTrackerCbAndGetSnapshot(
- activeSubscriptionGroups, subIdToGroupMap, true /* hasCarrierPrivileges */);
+ activeDataSubGrp,
+ activeSubscriptionGroups,
+ subIdToGroupMap,
+ true /* hasCarrierPrivileges */);
}
private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+ ParcelUuid activeDataSubGrp,
+ Set<ParcelUuid> activeSubscriptionGroups,
+ Map<Integer, ParcelUuid> subIdToGroupMap,
+ boolean hasCarrierPrivileges) {
+ return triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_SUBSCRIPTION_ID,
+ activeDataSubGrp,
+ activeSubscriptionGroups,
+ subIdToGroupMap,
+ hasCarrierPrivileges);
+ }
+
+ private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+ int activeDataSubId,
+ ParcelUuid activeDataSubGrp,
+ Set<ParcelUuid> activeSubscriptionGroups,
+ Map<Integer, ParcelUuid> subIdToGroupMap,
+ boolean hasCarrierPrivileges) {
+ final TelephonySubscriptionSnapshot snapshot =
+ buildSubscriptionSnapshot(
+ activeDataSubId,
+ activeDataSubGrp,
+ activeSubscriptionGroups,
+ subIdToGroupMap,
+ hasCarrierPrivileges);
+
+ final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+ cb.onNewSnapshot(snapshot);
+
+ return snapshot;
+ }
+
+ private TelephonySubscriptionSnapshot buildSubscriptionSnapshot(
+ int activeDataSubId,
+ ParcelUuid activeDataSubGrp,
Set<ParcelUuid> activeSubscriptionGroups,
Map<Integer, ParcelUuid> subIdToGroupMap,
boolean hasCarrierPrivileges) {
final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class);
doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups();
+ doReturn(activeDataSubGrp).when(snapshot).getActiveDataSubscriptionGroup();
+ doReturn(activeDataSubId).when(snapshot).getActiveDataSubscriptionId();
final Set<String> privilegedPackages =
(activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty())
@@ -343,12 +389,19 @@
return subIds;
}).when(snapshot).getAllSubIdsInGroup(any());
- final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
- cb.onNewSnapshot(snapshot);
-
return snapshot;
}
+ private void setupActiveSubscription(ParcelUuid activeDataSubGrp) {
+ mVcnMgmtSvc.setLastSnapshot(
+ buildSubscriptionSnapshot(
+ TEST_SUBSCRIPTION_ID,
+ activeDataSubGrp,
+ Collections.emptySet(),
+ Collections.emptyMap(),
+ true /* hasCarrierPrivileges */));
+ }
+
private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() {
final ArgumentCaptor<TelephonySubscriptionTrackerCallback> captor =
ArgumentCaptor.forClass(TelephonySubscriptionTrackerCallback.class);
@@ -372,25 +425,56 @@
@Test
public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception {
+ // Add a record for a non-active SIM
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
TelephonySubscriptionSnapshot snapshot =
- triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_1, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2)));
verify(mMockDeps)
.newVcnContext(
eq(mMockContext),
eq(mTestLooper.getLooper()),
any(VcnNetworkProvider.class),
anyBoolean());
+
+ // Verify that only the VCN for the active data SIM was started.
verify(mMockDeps)
.newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any());
+ verify(mMockDeps, never())
+ .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any());
+ }
+
+ @Test
+ public void testTelephonyNetworkTrackerCallbackSwitchingActiveDataStartsAndStopsInstances()
+ throws Exception {
+ // Add a record for a non-active SIM
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1);
+
+ TelephonySubscriptionSnapshot snapshot =
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_2, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2)));
+
+ // Verify that a new VCN for UUID_2 was started, and the old instance was torn down
+ // immediately
+ verify(mMockDeps)
+ .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any());
+ verify(vcn).teardownAsynchronously();
+ assertEquals(1, mVcnMgmtSvc.getAllVcns().size());
+ assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1));
+ assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2));
}
@Test
public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
- triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
+ triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
// Verify teardown after delay
mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
@@ -400,19 +484,76 @@
}
@Test
+ public void testTelephonyNetworkTrackerCallbackSwitchToNewSubscriptionImmediatelyTearsDown()
+ throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+ final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
+
+ // Simulate switch to different default data subscription that does not have a VCN.
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_SUBSCRIPTION_ID,
+ null /* activeDataSubscriptionGroup */,
+ Collections.emptySet(),
+ Collections.emptyMap(),
+ false /* hasCarrierPrivileges */);
+ mTestLooper.dispatchAll();
+
+ verify(vcn).teardownAsynchronously();
+ assertEquals(0, mVcnMgmtSvc.getAllVcns().size());
+ }
+
+ /**
+ * Tests an intermediate state where carrier privileges are marked as lost before active data
+ * subId changes during a SIM ejection.
+ *
+ * <p>The expected outcome is that the VCN is torn down after a delay, as opposed to
+ * immediately.
+ */
+ @Test
+ public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges()
+ throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
+ final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+ final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
+
+ // Simulate privileges lost
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_2,
+ Collections.emptySet(),
+ Collections.emptyMap(),
+ false /* hasCarrierPrivileges */);
+
+ // Verify teardown after delay
+ mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+ mTestLooper.dispatchAll();
+ verify(vcn).teardownAsynchronously();
+ }
+
+ @Test
public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances()
throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
// Simulate SIM unloaded
- triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ INVALID_SUBSCRIPTION_ID,
+ null /* activeDataSubscriptionGroup */,
+ Collections.emptySet(),
+ Collections.emptyMap(),
+ false /* hasCarrierPrivileges */);
// Simulate new SIM loaded right during teardown delay.
mTestLooper.moveTimeForward(
VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
mTestLooper.dispatchAll();
- triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2));
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
// Verify that even after the full timeout duration, the VCN instance is not torn down
mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
@@ -422,11 +563,13 @@
@Test
public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2);
// Simulate SIM unloaded
- triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
+ triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
// Config cleared, SIM reloaded & config re-added right before teardown delay, staring new
// vcnInstance.
@@ -434,6 +577,7 @@
VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
mTestLooper.dispatchAll();
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2);
// Verify that new instance was different, and the old one was torn down
@@ -538,6 +682,31 @@
}
@Test
+ public void testSetVcnConfigNonActiveSimDoesNotStartVcn() throws Exception {
+ // Use a different UUID to simulate a new VCN config.
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+
+ verify(mMockDeps, never()).newVcn(any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void testSetVcnConfigActiveSimTearsDownExistingVcnsImmediately() throws Exception {
+ final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1);
+
+ // Use a different UUID to simulate a new VCN config.
+ setupActiveSubscription(TEST_UUID_2);
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
+ verify(mMockDeps, times(2)).newVcn(any(), any(), any(), any(), any());
+ verify(vcn).teardownAsynchronously();
+ assertEquals(1, mVcnMgmtSvc.getAllVcns().size());
+ assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1));
+ assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2));
+ }
+
+ @Test
public void testSetVcnConfigTestModeRequiresPermission() throws Exception {
doThrow(new SecurityException("Requires MANAGE_TEST_NETWORKS"))
.when(mMockContext)
@@ -561,7 +730,7 @@
@Test
public void testSetVcnConfigNotifiesStatusCallback() throws Exception {
- triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2));
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
@@ -635,7 +804,9 @@
}
@Test
- public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTeardsDownVcns() throws Exception {
+ public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTearsDownVcns() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
// Use a different UUID to simulate a new VCN config.
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
@@ -646,12 +817,7 @@
// Verify Vcn is started
verify(mMockDeps)
- .newVcn(
- eq(mVcnContext),
- eq(TEST_UUID_2),
- eq(TEST_VCN_CONFIG),
- eq(TelephonySubscriptionSnapshot.EMPTY_SNAPSHOT),
- any());
+ .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), any(), any());
// Verify Vcn is updated if it was previously started
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
@@ -693,7 +859,7 @@
// Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are
// privileged for.
- triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
final List<ParcelUuid> subGrps =
mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
assertEquals(Collections.singletonList(TEST_UUID_1), subGrps);
@@ -760,6 +926,7 @@
int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) {
mVcnMgmtSvc.systemReady();
triggerSubscriptionTrackerCbAndGetSnapshot(
+ subGrp,
Collections.singleton(subGrp),
Collections.singletonMap(subId, subGrp),
hasCarrierPrivileges);
@@ -927,18 +1094,23 @@
@Test
public void testSubscriptionSnapshotUpdateNotifiesVcn() {
+ setupActiveSubscription(TEST_UUID_2);
+
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
TelephonySubscriptionSnapshot snapshot =
- triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2));
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_2, Collections.singleton(TEST_UUID_2));
verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot));
}
@Test
public void testAddNewVcnUpdatesPolicyListener() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
@@ -948,6 +1120,8 @@
@Test
public void testRemoveVcnUpdatesPolicyListener() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
@@ -958,10 +1132,13 @@
@Test
public void testVcnSubIdChangeUpdatesPolicyListener() throws Exception {
+ setupActiveSubscription(TEST_UUID_2);
+
startAndGetVcnInstance(TEST_UUID_2);
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_2,
Collections.singleton(TEST_UUID_2),
Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2));
@@ -988,7 +1165,8 @@
private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode)
throws Exception {
TelephonySubscriptionSnapshot snapshot =
- triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_1, Collections.singleton(TEST_UUID_1));
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
@@ -1014,7 +1192,8 @@
boolean hasPermissionsforSubGroup)
throws Exception {
TelephonySubscriptionSnapshot snapshot =
- triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup));
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ subGroup, Collections.singleton(subGroup));
setupSubscriptionAndStartVcn(
TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup);
@@ -1089,6 +1268,7 @@
// timeout so the VCN goes inactive.
final TelephonySubscriptionSnapshot snapshot =
triggerSubscriptionTrackerCbAndGetSnapshot(
+ TEST_UUID_1,
Collections.singleton(TEST_UUID_1),
Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1),
false /* hasCarrierPrivileges */);
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index ca74638..1f0df62 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -21,6 +21,7 @@
import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -54,6 +55,7 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.ArraySet;
@@ -178,6 +180,14 @@
return captor.getValue();
}
+ private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() {
+ final ArgumentCaptor<TelephonyCallback> captor =
+ ArgumentCaptor.forClass(TelephonyCallback.class);
+ verify(mTelephonyManager).registerTelephonyCallback(any(), captor.capture());
+
+ return (ActiveDataSubscriptionIdListener) captor.getValue();
+ }
+
private Intent buildTestBroadcastIntent(boolean hasValidSubscription) {
Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX);
@@ -196,7 +206,14 @@
private TelephonySubscriptionSnapshot buildExpectedSnapshot(
Map<Integer, SubscriptionInfo> subIdToInfoMap,
Map<ParcelUuid, Set<String>> privilegedPackages) {
- return new TelephonySubscriptionSnapshot(subIdToInfoMap, privilegedPackages);
+ return new TelephonySubscriptionSnapshot(0, subIdToInfoMap, privilegedPackages);
+ }
+
+ private TelephonySubscriptionSnapshot buildExpectedSnapshot(
+ int activeSubId,
+ Map<Integer, SubscriptionInfo> subIdToInfoMap,
+ Map<ParcelUuid, Set<String>> privilegedPackages) {
+ return new TelephonySubscriptionSnapshot(activeSubId, subIdToInfoMap, privilegedPackages);
}
private void verifyNoActiveSubscriptions() {
@@ -250,6 +267,26 @@
}
@Test
+ public void testOnSubscriptionsChangedFired_onActiveSubIdsChanged() throws Exception {
+ setupReadySubIds();
+ setPrivilegedPackagesForMock(Collections.emptyList());
+
+ doReturn(TEST_SUBSCRIPTION_ID_2).when(mDeps).getActiveDataSubscriptionId();
+ final ActiveDataSubscriptionIdListener listener = getActiveDataSubscriptionIdListener();
+ listener.onActiveDataSubscriptionIdChanged(TEST_SUBSCRIPTION_ID_2);
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor<TelephonySubscriptionSnapshot> snapshotCaptor =
+ ArgumentCaptor.forClass(TelephonySubscriptionSnapshot.class);
+ verify(mCallback).onNewSnapshot(snapshotCaptor.capture());
+
+ TelephonySubscriptionSnapshot snapshot = snapshotCaptor.getValue();
+ assertNotNull(snapshot);
+ assertEquals(TEST_SUBSCRIPTION_ID_2, snapshot.getActiveDataSubscriptionId());
+ assertEquals(TEST_PARCEL_UUID, snapshot.getActiveDataSubscriptionGroup());
+ }
+
+ @Test
public void testOnSubscriptionsChangedFired_WithReadySubidsNoPrivilegedPackages()
throws Exception {
setupReadySubIds();
@@ -371,7 +408,8 @@
@Test
public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception {
final TelephonySubscriptionSnapshot snapshot =
- new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap());
+ new TelephonySubscriptionSnapshot(
+ TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());
assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1));
assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2));
@@ -380,7 +418,8 @@
@Test
public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception {
final TelephonySubscriptionSnapshot snapshot =
- new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap());
+ new TelephonySubscriptionSnapshot(
+ TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());
assertEquals(
new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)),
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index b97023a..a696b3a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -127,7 +127,9 @@
protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
new TelephonySubscriptionSnapshot(
- Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), Collections.EMPTY_MAP);
+ TEST_SUB_ID,
+ Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO),
+ Collections.EMPTY_MAP);
@NonNull protected final Context mContext;
@NonNull protected final TestLooper mTestLooper;