diff options
35 files changed, 1066 insertions, 490 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 4036c988f3e5..a09a3597dab8 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -42283,7 +42283,8 @@ package android.telephony.euicc { method public boolean isEnabled(); method public boolean isSimPortAvailable(int); method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException; - method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent); + method @Deprecated @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent); + method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.euicc.EuiccManager.ResultListener); method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, @Nullable String, @NonNull android.app.PendingIntent); field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; field public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE"; @@ -42329,6 +42330,10 @@ package android.telephony.euicc { field public static final int OPERATION_SYSTEM = 1; // 0x1 } + public static interface EuiccManager.ResultListener { + method public void onComplete(int, @Nullable android.content.Intent); + } + } package android.telephony.gsm { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index cbfd86e5478f..77cc03c0cb39 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -9641,7 +9641,8 @@ package android.service.euicc { method @android.telephony.euicc.EuiccManager.OtaStatus public abstract int onGetOtaStatus(int); method public abstract int onRetainSubscriptionsForFactoryReset(int); method public abstract void onStartOtaIfNecessary(int, android.service.euicc.EuiccService.OtaStatusChangedCallback); - method public abstract int onSwitchToSubscription(int, @Nullable String, boolean); + method @Deprecated public abstract int onSwitchToSubscription(int, @Nullable String, boolean); + method public int onSwitchToSubscriptionWithPort(int, int, @Nullable String, boolean); method public abstract int onUpdateSubscriptionNickname(int, String, String); field public static final String ACTION_BIND_CARRIER_PROVISIONING_SERVICE = "android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE"; field public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = "android.service.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED"; @@ -9663,6 +9664,7 @@ package android.service.euicc { field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE"; field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED"; field public static final String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT"; + field public static final String EXTRA_RESOLUTION_PORT_INDEX = "android.service.euicc.extra.RESOLUTION_PORT_INDEX"; field public static final String EXTRA_RESOLVABLE_ERRORS = "android.service.euicc.extra.RESOLVABLE_ERRORS"; field public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1; // 0x1 field public static final int RESOLVABLE_ERROR_POLICY_RULES = 2; // 0x2 @@ -11594,7 +11596,6 @@ package android.telephony { } public class TelephonyManager { - method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addCarrierPrivilegesListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener); method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) @WorkerThread public void bootstrapAuthenticationRequest(int, @NonNull android.net.Uri, @NonNull android.telephony.gba.UaSecurityProtocolIdentifier, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.BootstrapAuthenticationCallback); method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult changeIccLockPin(@NonNull String, @NonNull String); @@ -11661,10 +11662,14 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int); - method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int); - method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String); - method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void iccCloseLogicalChannelByPort(int, int, int); + method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelByPort(int, int, @Nullable String, int); + method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelByPort(int, int, int, int, int, int, int, @Nullable String); + method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelByPort(int, int, int, int, int, int, int, int, @Nullable String); + method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int); @@ -11691,7 +11696,6 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerCarrierPrivilegesCallback(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesCallback); - method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeCarrierPrivilegesListener(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>); @@ -11851,10 +11855,6 @@ package android.telephony { method public default void onCarrierServiceChanged(@Nullable String, int); } - @Deprecated public static interface TelephonyManager.CarrierPrivilegesListener { - method @Deprecated public void onCarrierPrivilegesChanged(@NonNull java.util.List<java.lang.String>, @NonNull int[]); - } - public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception { ctor public TelephonyManager.ModemActivityInfoException(int); method public int getErrorCode(); diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 7be4c3e1465b..4c30f56e40d6 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -586,8 +586,9 @@ public abstract class ActivityManagerInternal { /** * Delete uid from the ActivityManagerService PendingStartActivityUids list. * @param uid uid + * @param nowElapsed starting time of updateOomAdj */ - public abstract void deletePendingTopUid(int uid); + public abstract void deletePendingTopUid(int uid, long nowElapsed); /** * Is the uid in ActivityManagerService PendingStartActivityUids list? diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java index ab741990430f..82d4443ea724 100644 --- a/core/java/android/os/SystemProperties.java +++ b/core/java/android/os/SystemProperties.java @@ -218,14 +218,15 @@ public class SystemProperties { /** * Set the value for the given {@code key} to {@code val}. * - * @throws IllegalArgumentException if the {@code val} exceeds 91 characters + * @throws IllegalArgumentException for non read-only properties if the {@code val} exceeds + * 91 characters * @throws RuntimeException if the property cannot be set, for example, if it was blocked by * SELinux. libc will log the underlying reason. * @hide */ @UnsupportedAppUsage public static void set(@NonNull String key, @Nullable String val) { - if (val != null && !val.startsWith("ro.") && val.length() > PROP_VALUE_MAX) { + if (val != null && !key.startsWith("ro.") && val.length() > PROP_VALUE_MAX) { throw new IllegalArgumentException("value of system property '" + key + "' is longer than " + PROP_VALUE_MAX + " characters: " + val); } diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java index 0cb69a4da50f..61fd0416e3b2 100644 --- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java +++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java @@ -167,10 +167,7 @@ public final class WrappedApplicationKey implements Parcelable { protected WrappedApplicationKey(Parcel in) { mAlias = in.readString(); mEncryptedKeyMaterial = in.createByteArray(); - // Check if there is still data to be read. - if (in.dataAvail() > 0) { - mMetadata = in.createByteArray(); - } + mMetadata = in.createByteArray(); } @Override diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index 542de3fad8b0..9c7f23e56617 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -27,6 +27,7 @@ import android.os.Binder; import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; +import android.service.carrier.CarrierService; import android.telephony.Annotation.CallState; import android.telephony.Annotation.DataActivityType; import android.telephony.Annotation.DisconnectCauses; @@ -36,7 +37,7 @@ import android.telephony.Annotation.PreciseDisconnectCauses; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; import android.telephony.Annotation.SrvccState; -import android.telephony.TelephonyManager.CarrierPrivilegesListener; +import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; import android.util.ArraySet; @@ -44,17 +45,19 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.listeners.ListenerExecutor; -import com.android.internal.telephony.ICarrierPrivilegesListener; +import com.android.internal.telephony.ICarrierPrivilegesCallback; import com.android.internal.telephony.IOnSubscriptionsChangedListener; import com.android.internal.telephony.ITelephonyRegistry; import java.lang.ref.WeakReference; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.Executor; +import java.util.stream.Collectors; /** * A centralized place to notify telephony related status changes, e.g, {@link ServiceState} update @@ -1258,63 +1261,79 @@ public class TelephonyRegistryManager { pkgName, attributionTag, callback, new int[0], notifyNow); } - private static class CarrierPrivilegesListenerWrapper extends ICarrierPrivilegesListener.Stub + private static class CarrierPrivilegesCallbackWrapper extends ICarrierPrivilegesCallback.Stub implements ListenerExecutor { - private final WeakReference<CarrierPrivilegesListener> mListener; - private final Executor mExecutor; + @NonNull private final WeakReference<CarrierPrivilegesCallback> mCallback; + @NonNull private final Executor mExecutor; - CarrierPrivilegesListenerWrapper(CarrierPrivilegesListener listener, Executor executor) { - mListener = new WeakReference<>(listener); + CarrierPrivilegesCallbackWrapper( + @NonNull CarrierPrivilegesCallback callback, @NonNull Executor executor) { + mCallback = new WeakReference<>(callback); mExecutor = executor; } @Override public void onCarrierPrivilegesChanged( - List<String> privilegedPackageNames, int[] privilegedUids) { + @NonNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids) { + // AIDL interface does not support Set, keep the List/Array and translate them here + Set<String> privilegedPkgNamesSet = Set.copyOf(privilegedPackageNames); + Set<Integer> privilegedUidsSet = Arrays.stream(privilegedUids).boxed().collect( + Collectors.toSet()); Binder.withCleanCallingIdentity( () -> executeSafely( mExecutor, - mListener::get, - cpl -> - cpl.onCarrierPrivilegesChanged( - privilegedPackageNames, privilegedUids))); + mCallback::get, + cpc -> + cpc.onCarrierPrivilegesChanged( + privilegedPkgNamesSet, privilegedUidsSet))); + } + + @Override + public void onCarrierServiceChanged(@Nullable String packageName, int uid) { + Binder.withCleanCallingIdentity( + () -> + executeSafely( + mExecutor, + mCallback::get, + cpc -> cpc.onCarrierServiceChanged(packageName, uid))); } } - @GuardedBy("sCarrierPrivilegeListeners") - private static final WeakHashMap< - CarrierPrivilegesListener, WeakReference<CarrierPrivilegesListenerWrapper>> - sCarrierPrivilegeListeners = new WeakHashMap<>(); + @NonNull + @GuardedBy("sCarrierPrivilegeCallbacks") + private static final WeakHashMap<CarrierPrivilegesCallback, + WeakReference<CarrierPrivilegesCallbackWrapper>> + sCarrierPrivilegeCallbacks = new WeakHashMap<>(); /** - * Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to + * Registers a {@link CarrierPrivilegesCallback} on the given {@code logicalSlotIndex} to * receive callbacks when the set of packages with carrier privileges changes. The callback will * immediately be called with the latest state. * * @param logicalSlotIndex The SIM slot to listen on * @param executor The executor where {@code listener} will be invoked - * @param listener The callback to register + * @param callback The callback to register */ - public void addCarrierPrivilegesListener( + public void addCarrierPrivilegesCallback( int logicalSlotIndex, @NonNull @CallbackExecutor Executor executor, - @NonNull CarrierPrivilegesListener listener) { - if (listener == null || executor == null) { - throw new IllegalArgumentException("listener and executor must be non-null"); + @NonNull CarrierPrivilegesCallback callback) { + if (callback == null || executor == null) { + throw new IllegalArgumentException("callback and executor must be non-null"); } - synchronized (sCarrierPrivilegeListeners) { - WeakReference<CarrierPrivilegesListenerWrapper> existing = - sCarrierPrivilegeListeners.get(listener); + synchronized (sCarrierPrivilegeCallbacks) { + WeakReference<CarrierPrivilegesCallbackWrapper> existing = + sCarrierPrivilegeCallbacks.get(callback); if (existing != null && existing.get() != null) { - Log.d(TAG, "addCarrierPrivilegesListener: listener already registered"); + Log.d(TAG, "addCarrierPrivilegesCallback: callback already registered"); return; } - CarrierPrivilegesListenerWrapper wrapper = - new CarrierPrivilegesListenerWrapper(listener, executor); - sCarrierPrivilegeListeners.put(listener, new WeakReference<>(wrapper)); + CarrierPrivilegesCallbackWrapper wrapper = + new CarrierPrivilegesCallbackWrapper(callback, executor); + sCarrierPrivilegeCallbacks.put(callback, new WeakReference<>(wrapper)); try { - sRegistry.addCarrierPrivilegesListener( + sRegistry.addCarrierPrivilegesCallback( logicalSlotIndex, wrapper, mContext.getOpPackageName(), @@ -1326,22 +1345,22 @@ public class TelephonyRegistryManager { } /** - * Unregisters a {@link CarrierPrivilegesListener}. + * Unregisters a {@link CarrierPrivilegesCallback}. * - * @param listener The callback to unregister + * @param callback The callback to unregister */ - public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) { - if (listener == null) { + public void removeCarrierPrivilegesCallback(@NonNull CarrierPrivilegesCallback callback) { + if (callback == null) { throw new IllegalArgumentException("listener must be non-null"); } - synchronized (sCarrierPrivilegeListeners) { - WeakReference<CarrierPrivilegesListenerWrapper> ref = - sCarrierPrivilegeListeners.remove(listener); + synchronized (sCarrierPrivilegeCallbacks) { + WeakReference<CarrierPrivilegesCallbackWrapper> ref = + sCarrierPrivilegeCallbacks.remove(callback); if (ref == null) return; - CarrierPrivilegesListenerWrapper wrapper = ref.get(); + CarrierPrivilegesCallbackWrapper wrapper = ref.get(); if (wrapper == null) return; try { - sRegistry.removeCarrierPrivilegesListener(wrapper, mContext.getOpPackageName()); + sRegistry.removeCarrierPrivilegesCallback(wrapper, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1357,15 +1376,33 @@ public class TelephonyRegistryManager { */ public void notifyCarrierPrivilegesChanged( int logicalSlotIndex, - @NonNull List<String> privilegedPackageNames, - @NonNull int[] privilegedUids) { + @NonNull Set<String> privilegedPackageNames, + @NonNull Set<Integer> privilegedUids) { if (privilegedPackageNames == null || privilegedUids == null) { throw new IllegalArgumentException( "privilegedPackageNames and privilegedUids must be non-null"); } try { - sRegistry.notifyCarrierPrivilegesChanged( - logicalSlotIndex, privilegedPackageNames, privilegedUids); + // AIDL doesn't support Set yet. Convert Set to List/Array + List<String> pkgList = List.copyOf(privilegedPackageNames); + int[] uids = privilegedUids.stream().mapToInt(Number::intValue).toArray(); + sRegistry.notifyCarrierPrivilegesChanged(logicalSlotIndex, pkgList, uids); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Notify listeners that the {@link CarrierService} for current user has changed. + * + * @param logicalSlotIndex the SIM slot the change occurred on + * @param packageName the package name of the changed {@link CarrierService} + * @param uid the UID of the changed {@link CarrierService} + */ + public void notifyCarrierServiceChanged(int logicalSlotIndex, @Nullable String packageName, + int uid) { + try { + sRegistry.notifyCarrierServiceChanged(logicalSlotIndex, packageName, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 9cb0d1ff2c3f..a06b0e0355d8 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -741,35 +741,42 @@ public final class Display { } /** - * Gets the size of the display, in pixels. - * Value returned by this method does not necessarily represent the actual raw size - * (native resolution) of the display. - * <p> - * 1. The returned size may be adjusted to exclude certain system decor elements - * that are always visible. - * </p><p> - * 2. It may be scaled to provide compatibility with older applications that - * were originally designed for smaller displays. - * </p><p> - * 3. It can be different depending on the WindowManager to which the display belongs. - * </p><p> - * - If requested from non-Activity context (e.g. Application context via - * {@code (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE)}) - * it will report the size of the entire display based on current rotation and with subtracted - * system decoration areas. - * </p><p> - * - If requested from activity (either using {@code getWindowManager()} or - * {@code (WindowManager) getSystemService(Context.WINDOW_SERVICE)}) resulting size will - * correspond to current app window size. In this case it can be smaller than physical size in - * multi-window mode. - * </p><p> - * Typically for the purposes of layout apps should make a request from activity context - * to obtain size available for the app content. - * </p> + * Gets the size of the display in pixels. + * + * <p>The return value does not necessarily represent the actual size (native resolution) of the + * display. The returned size might be adjusted to exclude certain system decor elements that + * are always visible, or the size might be scaled to provide compatibility with older + * applications that were originally designed for smaller displays. + * + * <p>The returned size can also be different depending on the WindowManager bound to the + * display: + * <ul> + * <li>If size is requested from an activity (either using a WindowManager accessed by + * {@code getWindowManager()} or {@code getSystemService(Context.WINDOW_SERVICE)}), the + * size of the current app window is returned. As a result, in multi-window mode, the + * returned size can be smaller than the size of the device screen. + * <li>If size is requested from a non-activity context (for example, the application + * context, where the WindowManager is accessed by + * {@code getApplicationContext().getSystemService(Context.WINDOW_SERVICE)}), the + * returned size can vary depending on API level: + * <ul> + * <li>API level 29 and below — The size of the entire display (based on + * current rotation) minus system decoration areas is returned. + * <li>API level 30 and above — The size of the top running activity in the + * current process is returned. If the current process has no running + * activities, the size of the device default display, including system + * decoration areas, is returned. + * </ul> + * </ul> + * + * <p>For layout purposes, apps should make a request from an activity context to obtain the + * size of the display area available for app content. + * + * @param outSize A {@link Point} object which receives the display size information. * - * @param outSize A {@link Point} object to receive the size information. - * @deprecated Use {@link WindowManager#getCurrentWindowMetrics()} to obtain an instance of - * {@link WindowMetrics} and use {@link WindowMetrics#getBounds()} instead. + * @deprecated Use {@link WindowMetrics} instead. Obtain a {@code WindowMetrics} instance by + * calling {@link WindowManager#getCurrentWindowMetrics()}, then call + * {@link WindowMetrics#getBounds()} to get the dimensions of the application window. */ @Deprecated public void getSize(Point outSize) { @@ -785,8 +792,9 @@ public final class Display { * Gets the size of the display as a rectangle, in pixels. * * @param outSize A {@link Rect} object to receive the size information. + * * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application - * window area. + * window. */ @Deprecated public void getRectSize(Rect outSize) { @@ -1275,32 +1283,39 @@ public final class Display { } /** - * Gets display metrics that describe the size and density of this display. - * The size returned by this method does not necessarily represent the - * actual raw size (native resolution) of the display. - * <p> - * 1. The returned size may be adjusted to exclude certain system decor elements - * that are always visible. - * </p><p> - * 2. It may be scaled to provide compatibility with older applications that - * were originally designed for smaller displays. - * </p><p> - * 3. It can be different depending on the WindowManager to which the display belongs. - * </p><p> - * - If requested from non-Activity context (e.g. Application context via - * {@code (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE)}) - * metrics will report the size of the entire display based on current rotation and with - * subtracted system decoration areas. - * </p><p> - * - If requested from activity (either using {@code getWindowManager()} or - * {@code (WindowManager) getSystemService(Context.WINDOW_SERVICE)}) resulting metrics will - * correspond to current app window metrics. In this case the size can be smaller than physical - * size in multi-window mode. - * </p> + * Gets the size and density of this display. + * + * <p>The size returned does not necessarily represent the actual size (native resolution) of + * the display. The returned size might be adjusted to exclude certain system decor elements + * that are always visible, or the size might be scaled to provide compatibility with older + * applications that were originally designed for smaller displays. + * + * <p>The returned size can also be different depending on the WindowManager associated with the + * display: + * <ul> + * <li>If metrics are requested from an activity (either using a WindowManager accessed by + * {@code getWindowManager()} or {@code getSystemService(Context.WINDOW_SERVICE)}), the + * returned metrics provide the size of the current app window. As a result, in + * multi-window mode, the returned size can be smaller than the size of the device + * screen. + * <li>If metrics are requested from a non-activity context (for example, the application + * context, where the WindowManager is accessed by + * {@code getApplicationContext().getSystemService(Context.WINDOW_SERVICE)}), the + * returned size can vary depending on API level: + * <ul> + * <li>API level 29 and below — The returned metrics provide the size of the + * entire display (based on current rotation) minus system decoration areas. + * <li>API level 30 and above — The returned metrics provide the size of the + * top running activity in the current process. If the current process has no + * running activities, the metrics provide the size of the default display of + * the device, including system decoration areas. + * </ul> + * </ul> + * + * @param outMetrics A {@link DisplayMetrics} object which receives the display metrics. * - * @param outMetrics A {@link DisplayMetrics} object to receive the metrics. * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application - * window area, and {@link Configuration#densityDpi} to get the current density. + * window. Use {@link Configuration#densityDpi} to get the display density. */ @Deprecated public void getMetrics(DisplayMetrics outMetrics) { diff --git a/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl b/core/java/com/android/internal/telephony/ICarrierPrivilegesCallback.aidl index 6ca8cecba3c8..0c8e73fb2b67 100644 --- a/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl +++ b/core/java/com/android/internal/telephony/ICarrierPrivilegesCallback.aidl @@ -16,7 +16,8 @@ package com.android.internal.telephony; -oneway interface ICarrierPrivilegesListener { +oneway interface ICarrierPrivilegesCallback { void onCarrierPrivilegesChanged( in List<String> privilegedPackageNames, in int[] privilegedUids); + void onCarrierServiceChanged(in String carrierServicePackageName, in int carrierServiceUid); } diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 9712d7e38a4b..c7fa757ac0b7 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -32,7 +32,7 @@ import android.telephony.PreciseDataConnectionState; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.emergency.EmergencyNumber; -import com.android.internal.telephony.ICarrierPrivilegesListener; +import com.android.internal.telephony.ICarrierPrivilegesCallback; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.IOnSubscriptionsChangedListener; @@ -102,9 +102,11 @@ interface ITelephonyRegistry { void notifyLinkCapacityEstimateChanged(in int phoneId, in int subId, in List<LinkCapacityEstimate> linkCapacityEstimateList); - void addCarrierPrivilegesListener( - int phoneId, ICarrierPrivilegesListener callback, String pkg, String featureId); - void removeCarrierPrivilegesListener(ICarrierPrivilegesListener callback, String pkg); + void addCarrierPrivilegesCallback( + int phoneId, ICarrierPrivilegesCallback callback, String pkg, String featureId); + void removeCarrierPrivilegesCallback(ICarrierPrivilegesCallback callback, String pkg); void notifyCarrierPrivilegesChanged( int phoneId, in List<String> privilegedPackageNames, in int[] privilegedUids); + void notifyCarrierServiceChanged(int phoneId, in String packageName, int uid); + } diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java index 05fb4c3cf76f..919a93b8f107 100644 --- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java +++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.ServiceManager; import android.os.ServiceSpecificException; -import android.security.keystore.KeyProperties; import android.security.maintenance.IKeystoreMaintenance; import android.system.keystore2.Domain; import android.system.keystore2.KeyDescriptor; @@ -158,11 +157,6 @@ public class AndroidKeyStoreMaintenance { * Migrates a key given by the source descriptor to the location designated by the destination * descriptor. * - * If Domain::APP is selected in either source or destination, nspace must be set to - * {@link KeyProperties#NAMESPACE_APPLICATION}, implying the caller's UID. - * If the caller has the MIGRATE_ANY_KEY permission, Domain::APP may be used with - * other nspace values which then indicates the UID of a different application. - * * @param source - The key to migrate may be specified by Domain.APP, Domain.SELINUX, or * Domain.KEY_ID. The caller needs the permissions use, delete, and grant for the * source namespace. @@ -189,20 +183,4 @@ public class AndroidKeyStoreMaintenance { return SYSTEM_ERROR; } } - - /** - * @see IKeystoreMaintenance#listEntries(int, long) - */ - @Nullable - public static KeyDescriptor[] listEntries(int domain, long nspace) { - try { - return getService().listEntries(domain, nspace); - } catch (ServiceSpecificException e) { - Log.e(TAG, "listEntries failed", e); - return null; - } catch (Exception e) { - Log.e(TAG, "Can not connect to keystore", e); - return null; - } - } } diff --git a/libs/WindowManager/Jetpack/tests/OWNERS b/libs/WindowManager/Jetpack/tests/OWNERS new file mode 100644 index 000000000000..f2c3388023be --- /dev/null +++ b/libs/WindowManager/Jetpack/tests/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 909476 +# includes OWNERS from parent directories +charlesccchen@google.com +diegovela@google.com diff --git a/packages/ConnectivityT/OWNERS b/packages/ConnectivityT/OWNERS index e267d19ad7e2..adbcd4b5a36b 100644 --- a/packages/ConnectivityT/OWNERS +++ b/packages/ConnectivityT/OWNERS @@ -1,2 +1,5 @@ -file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking -per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS +# OWNERS block for code move: b/222234190 +reminv@google.com + +# file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking +# per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java index 4f61dbf38b24..e02ea897dbe6 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java @@ -39,8 +39,10 @@ import com.android.modules.utils.BackgroundThread; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; +import java.util.function.IntConsumer; /** * A class that manages and configures Ethernet interfaces. @@ -53,15 +55,31 @@ public class EthernetManager { private static final String TAG = "EthernetManager"; private final IEthernetManager mService; - @GuardedBy("mListeners") - private final ArrayList<ListenerInfo> mListeners = new ArrayList<>(); + @GuardedBy("mListenerLock") + private final ArrayList<ListenerInfo<InterfaceStateListener>> mIfaceListeners = + new ArrayList<>(); + @GuardedBy("mListenerLock") + private final ArrayList<ListenerInfo<IntConsumer>> mEthernetStateListeners = + new ArrayList<>(); + final Object mListenerLock = new Object(); private final IEthernetServiceListener.Stub mServiceListener = new IEthernetServiceListener.Stub() { @Override + public void onEthernetStateChanged(int state) { + synchronized (mListenerLock) { + for (ListenerInfo<IntConsumer> li : mEthernetStateListeners) { + li.executor.execute(() -> { + li.listener.accept(state); + }); + } + } + } + + @Override public void onInterfaceStateChanged(String iface, int state, int role, IpConfiguration configuration) { - synchronized (mListeners) { - for (ListenerInfo li : mListeners) { + synchronized (mListenerLock) { + for (ListenerInfo<InterfaceStateListener> li : mIfaceListeners) { li.executor.execute(() -> li.listener.onInterfaceStateChanged(iface, state, role, configuration)); @@ -70,13 +88,29 @@ public class EthernetManager { } }; - private static class ListenerInfo { + /** + * Indicates that Ethernet is disabled. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ETHERNET_STATE_DISABLED = 0; + + /** + * Indicates that Ethernet is enabled. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ETHERNET_STATE_ENABLED = 1; + + private static class ListenerInfo<T> { @NonNull public final Executor executor; @NonNull - public final InterfaceStateListener listener; + public final T listener; - private ListenerInfo(@NonNull Executor executor, @NonNull InterfaceStateListener listener) { + private ListenerInfo(@NonNull Executor executor, @NonNull T listener) { this.executor = executor; this.listener = listener; } @@ -289,16 +323,22 @@ public class EthernetManager { if (listener == null || executor == null) { throw new NullPointerException("listener and executor must not be null"); } - synchronized (mListeners) { - mListeners.add(new ListenerInfo(executor, listener)); - if (mListeners.size() == 1) { - try { - mService.addListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + synchronized (mListenerLock) { + maybeAddServiceListener(); + mIfaceListeners.add(new ListenerInfo<InterfaceStateListener>(executor, listener)); + } + } + + @GuardedBy("mListenerLock") + private void maybeAddServiceListener() { + if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return; + + try { + mService.addListener(mServiceListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } + } /** @@ -323,15 +363,20 @@ public class EthernetManager { @SystemApi(client = MODULE_LIBRARIES) public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) { Objects.requireNonNull(listener); - synchronized (mListeners) { - mListeners.removeIf(l -> l.listener == listener); - if (mListeners.isEmpty()) { - try { - mService.removeListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + synchronized (mListenerLock) { + mIfaceListeners.removeIf(l -> l.listener == listener); + maybeRemoveServiceListener(); + } + } + + @GuardedBy("mListenerLock") + private void maybeRemoveServiceListener() { + if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return; + + try { + mService.removeListener(mServiceListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -535,14 +580,13 @@ public class EthernetManager { } /** - * Set an ethernet network's link state up. + * Enable a network interface. * - * When the link is successfully turned up, the callback will be called with the network - * interface was torn down, if any. If any error or unexpected condition happens while the - * system tries to turn the interface down, the callback will be called with an appropriate - * exception. The callback is guaranteed to be called exactly once for each call to this method. + * Enables a previously disabled network interface. + * This function accepts an {@link OutcomeReceiver} that is called once the operation has + * finished execution. * - * @param iface the name of the interface to act upon. + * @param iface the name of the interface to enable. * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. * @param callback an optional {@link OutcomeReceiver} to listen for completion of the * operation. On success, {@link OutcomeReceiver#onResult} is called with the @@ -550,7 +594,6 @@ public class EthernetManager { * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @throws UnsupportedOperationException if called on a non-automotive device. * @hide */ @SystemApi @@ -559,7 +602,7 @@ public class EthernetManager { android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) - public void connectNetwork( + public void enableInterface( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) { @@ -574,14 +617,14 @@ public class EthernetManager { } /** - * Set an ethernet network's link state down. + * Disable a network interface. * - * When the link is successfully turned down, the callback will be called with the network - * interface was torn down, if any. If any error or unexpected condition happens while the - * system tries to turn the interface down, the callback will be called with an appropriate - * exception. The callback is guaranteed to be called exactly once for each call to this method. + * Disables the use of a network interface to fulfill network requests. If the interface + * currently serves a request, the network will be torn down. + * This function accepts an {@link OutcomeReceiver} that is called once the operation has + * finished execution. * - * @param iface the name of the interface to act upon. + * @param iface the name of the interface to disable. * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. * @param callback an optional {@link OutcomeReceiver} to listen for completion of the * operation. On success, {@link OutcomeReceiver#onResult} is called with the @@ -589,7 +632,6 @@ public class EthernetManager { * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @throws UnsupportedOperationException if called on a non-automotive device. * @hide */ @SystemApi @@ -598,7 +640,7 @@ public class EthernetManager { android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) - public void disconnectNetwork( + public void disableInterface( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) { @@ -611,4 +653,77 @@ public class EthernetManager { throw e.rethrowFromSystemServer(); } } + + /** + * Change ethernet setting. + * + * @param enabled enable or disable ethernet settings. + * + * @hide + */ + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS}) + @SystemApi(client = MODULE_LIBRARIES) + public void setEthernetEnabled(boolean enabled) { + try { + mService.setEthernetEnabled(enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Listen to changes in the state of ethernet. + * + * @param executor to run callbacks on. + * @param listener to listen ethernet state changed. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + public void addEthernetStateListener(@NonNull Executor executor, + @NonNull IntConsumer listener) { + Objects.requireNonNull(executor); + Objects.requireNonNull(listener); + synchronized (mListenerLock) { + maybeAddServiceListener(); + mEthernetStateListeners.add(new ListenerInfo<IntConsumer>(executor, listener)); + } + } + + /** + * Removes a listener. + * + * @param listener to listen ethernet state changed. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + public void removeEthernetStateListener(@NonNull IntConsumer listener) { + Objects.requireNonNull(listener); + synchronized (mListenerLock) { + mEthernetStateListeners.removeIf(l -> l.listener == listener); + maybeRemoveServiceListener(); + } + } + + /** + * Returns an array of existing Ethernet interface names regardless whether the interface + * is available or not currently. + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + @NonNull + public List<String> getInterfaceList() { + try { + return mService.getInterfaceList(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } } diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl index 95ae907a3d21..42e4c1ac55aa 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl @@ -23,6 +23,8 @@ import android.net.EthernetNetworkUpdateRequest; import android.net.INetworkInterfaceOutcomeReceiver; import android.net.ITetheredInterfaceCallback; +import java.util.List; + /** * Interface that answers queries about, and allows changing * ethernet configuration. @@ -43,4 +45,6 @@ interface IEthernetManager in INetworkInterfaceOutcomeReceiver listener); void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); + void setEthernetEnabled(boolean enabled); + List<String> getInterfaceList(); } diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl index 6d2ba03f78d4..751605bb3849 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl @@ -21,6 +21,7 @@ import android.net.IpConfiguration; /** @hide */ oneway interface IEthernetServiceListener { + void onEthernetStateChanged(int state); void onInterfaceStateChanged(String iface, int state, int role, in IpConfiguration configuration); } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 382359ab1da5..06b331164083 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -91,7 +91,7 @@ import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; -import com.android.internal.telephony.ICarrierPrivilegesListener; +import com.android.internal.telephony.ICarrierPrivilegesCallback; import com.android.internal.telephony.IOnSubscriptionsChangedListener; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.ITelephonyRegistry; @@ -151,7 +151,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { IPhoneStateListener callback; IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback; IOnSubscriptionsChangedListener onOpportunisticSubscriptionsChangedListenerCallback; - ICarrierPrivilegesListener carrierPrivilegesListener; + ICarrierPrivilegesCallback carrierPrivilegesCallback; int callerUid; int callerPid; @@ -176,8 +176,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return (onOpportunisticSubscriptionsChangedListenerCallback != null); } - boolean matchCarrierPrivilegesListener() { - return carrierPrivilegesListener != null; + boolean matchCarrierPrivilegesCallback() { + return carrierPrivilegesCallback != null; } boolean canReadCallLog() { @@ -197,7 +197,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { + onSubscriptionsChangedListenerCallback + " onOpportunisticSubscriptionsChangedListenererCallback=" + onOpportunisticSubscriptionsChangedListenerCallback - + " carrierPrivilegesListener=" + carrierPrivilegesListener + + " carrierPrivilegesCallback=" + carrierPrivilegesCallback + " subId=" + subId + " phoneId=" + phoneId + " events=" + eventList + "}"; } } @@ -412,7 +412,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPreciseDataConnectionStates; /** Per-phoneId snapshot of privileged packages (names + UIDs). */ - private List<Pair<List<String>, int[]>> mCarrierPrivilegeStates; + @NonNull private List<Pair<List<String>, int[]>> mCarrierPrivilegeStates; + /** Per-phoneId of CarrierService (PackageName, UID) pair. */ + @NonNull private List<Pair<String, Integer>> mCarrierServiceStates; /** * Support backward compatibility for {@link android.telephony.TelephonyDisplayInfo}. @@ -702,22 +704,23 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { cutListToSize(mPhysicalChannelConfigs, mNumPhones); cutListToSize(mLinkCapacityEstimateLists, mNumPhones); cutListToSize(mCarrierPrivilegeStates, mNumPhones); + cutListToSize(mCarrierServiceStates, mNumPhones); return; } // mNumPhones > oldNumPhones: ss -> ds switch for (int i = oldNumPhones; i < mNumPhones; i++) { - mCallState[i] = TelephonyManager.CALL_STATE_IDLE; + mCallState[i] = TelephonyManager.CALL_STATE_IDLE; mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN; mVoiceActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN; mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN; - mCallIncomingNumber[i] = ""; - mServiceState[i] = new ServiceState(); - mSignalStrength[i] = null; + mCallIncomingNumber[i] = ""; + mServiceState[i] = new ServiceState(); + mSignalStrength[i] = null; mUserMobileDataState[i] = false; - mMessageWaiting[i] = false; - mCallForwarding[i] = false; + mMessageWaiting[i] = false; + mCallForwarding[i] = false; mCellIdentity[i] = null; mCellInfo.add(i, null); mImsReasonInfo.add(i, null); @@ -743,6 +746,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0])); + mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID)); } } @@ -809,6 +813,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataEnabledReason = new int[numPhones]; mLinkCapacityEstimateLists = new ArrayList<>(); mCarrierPrivilegeStates = new ArrayList<>(); + mCarrierServiceStates = new ArrayList<>(); for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; @@ -847,6 +852,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0])); + mCarrierServiceStates.add(i, new Pair<>(null, Process.INVALID_UID)); } mAppOps = mContext.getSystemService(AppOpsManager.class); @@ -2780,16 +2786,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override - public void addCarrierPrivilegesListener( + public void addCarrierPrivilegesCallback( int phoneId, - ICarrierPrivilegesListener callback, - String callingPackage, - String callingFeatureId) { + @NonNull ICarrierPrivilegesCallback callback, + @NonNull String callingPackage, + @NonNull String callingFeatureId) { int callerUserId = UserHandle.getCallingUserId(); mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, - "addCarrierPrivilegesListener"); + "addCarrierPrivilegesCallback"); if (VDBG) { log( "listen carrier privs: E pkg=" + pii(callingPackage) + " phoneId=" + phoneId @@ -2809,7 +2815,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (r == null) return; r.context = mContext; - r.carrierPrivilegesListener = callback; + r.carrierPrivilegesCallback = callback; r.callingPackage = callingPackage; r.callingFeatureId = callingFeatureId; r.callerUid = Binder.getCallingUid(); @@ -2821,10 +2827,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } Pair<List<String>, int[]> state = mCarrierPrivilegeStates.get(phoneId); + Pair<String, Integer> carrierServiceState = mCarrierServiceStates.get(phoneId); try { - r.carrierPrivilegesListener.onCarrierPrivilegesChanged( - Collections.unmodifiableList(state.first), - Arrays.copyOf(state.second, state.second.length)); + if (r.matchCarrierPrivilegesCallback()) { + // Here, two callbacks are triggered in quick succession on the same binder. + // In typical case, we expect the callers to care about only one or the other. + r.carrierPrivilegesCallback.onCarrierPrivilegesChanged( + Collections.unmodifiableList(state.first), + Arrays.copyOf(state.second, state.second.length)); + + r.carrierPrivilegesCallback.onCarrierServiceChanged(carrierServiceState.first, + carrierServiceState.second); + } } catch (RemoteException ex) { remove(r.binder); } @@ -2832,12 +2846,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override - public void removeCarrierPrivilegesListener( - ICarrierPrivilegesListener callback, String callingPackage) { + public void removeCarrierPrivilegesCallback( + @NonNull ICarrierPrivilegesCallback callback, @NonNull String callingPackage) { mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, - "removeCarrierPrivilegesListener"); + "removeCarrierPrivilegesCallback"); remove(callback.asBinder()); } @@ -2860,13 +2874,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { // Listeners are per-slot, not per-subscription. This is to provide a stable // view across SIM profile switches. - if (!r.matchCarrierPrivilegesListener() + if (!r.matchCarrierPrivilegesCallback() || !idMatch(r, SubscriptionManager.INVALID_SUBSCRIPTION_ID, phoneId)) { continue; } try { // Make sure even in-process listeners can't modify the values. - r.carrierPrivilegesListener.onCarrierPrivilegesChanged( + r.carrierPrivilegesCallback.onCarrierPrivilegesChanged( Collections.unmodifiableList(privilegedPackageNames), Arrays.copyOf(privilegedUids, privilegedUids.length)); } catch (RemoteException ex) { @@ -2878,6 +2892,34 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override + public void notifyCarrierServiceChanged(int phoneId, @Nullable String packageName, int uid) { + if (!checkNotifyPermission("notifyCarrierServiceChanged")) return; + if (!validatePhoneId(phoneId)) return; + if (VDBG) { + log("notifyCarrierServiceChanged: phoneId=" + phoneId + + ", package=" + pii(packageName) + ", uid=" + uid); + } + + synchronized (mRecords) { + mCarrierServiceStates.set( + phoneId, new Pair<>(packageName, uid)); + for (Record r : mRecords) { + // Listeners are per-slot, not per-subscription. + if (!r.matchCarrierPrivilegesCallback() + || !idMatch(r, SubscriptionManager.INVALID_SUBSCRIPTION_ID, phoneId)) { + continue; + } + try { + r.carrierPrivilegesCallback.onCarrierServiceChanged(packageName, uid); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + handleRemoveListLocked(); + } + } + + @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); @@ -2931,6 +2973,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println( "mCarrierPrivilegeState=<packages=" + pii(carrierPrivilegeState.first) + ", uids=" + Arrays.toString(carrierPrivilegeState.second) + ">"); + Pair<String, Integer> carrierServiceState = mCarrierServiceStates.get(i); + pw.println("mCarrierServiceState=<package=" + pii(carrierServiceState.first) + + ", uid=" + carrierServiceState.second + ">"); pw.decreaseIndent(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f978b2b68e48..0f450e16be2d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -16306,8 +16306,8 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void deletePendingTopUid(int uid) { - mPendingStartActivityUids.delete(uid); + public void deletePendingTopUid(int uid, long nowElapsed) { + mPendingStartActivityUids.delete(uid, nowElapsed); } @Override diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 96ea6db0c3f5..9e0441004568 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1378,7 +1378,7 @@ public class OomAdjuster { mService.mServices.foregroundServiceProcStateChangedLocked(uidRec); } } - mService.mInternal.deletePendingTopUid(uidRec.getUid()); + mService.mInternal.deletePendingTopUid(uidRec.getUid(), nowElapsed); } if (mLocalPowerManager != null) { mLocalPowerManager.finishUidChanges(); diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java index 6bf9d4e5c3f0..20f6bb205dc4 100644 --- a/services/core/java/com/android/server/am/PendingStartActivityUids.java +++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java @@ -50,9 +50,15 @@ final class PendingStartActivityUids { } } - synchronized void delete(int uid) { + synchronized void delete(int uid, long nowElapsed) { final Pair<Integer, Long> pendingPid = mPendingUids.get(uid); if (pendingPid != null) { + if (nowElapsed < pendingPid.second) { + Slog.i(TAG, + "updateOomAdj start time is before than pendingPid added," + + " don't delete it"); + return; + } final long delay = SystemClock.elapsedRealtime() - pendingPid.second; if (delay >= 1000 /*ms*/) { Slog.i(TAG, @@ -75,4 +81,4 @@ final class PendingStartActivityUids { synchronized boolean isPendingTopUid(int uid) { return mPendingUids.get(uid) != null; } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 470aa0e22c3f..67b44696d326 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -4127,7 +4127,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (mRestrictedNetworkingMode) { // Note: setUidFirewallRule also updates mUidFirewallRestrictedModeRules. // In this case, default firewall rules can also be added. - setUidFirewallRule(FIREWALL_CHAIN_RESTRICTED, uid, + setUidFirewallRuleUL(FIREWALL_CHAIN_RESTRICTED, uid, getRestrictedModeFirewallRule(uidBlockedState)); } } @@ -4291,9 +4291,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, chain == FIREWALL_CHAIN_DOZABLE); if (isWhitelisted || isUidForegroundOnRestrictPowerUL(uid)) { - setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW); + setUidFirewallRuleUL(chain, uid, FIREWALL_RULE_ALLOW); } else { - setUidFirewallRule(chain, uid, FIREWALL_RULE_DEFAULT); + setUidFirewallRuleUL(chain, uid, FIREWALL_RULE_DEFAULT); } } } @@ -4339,10 +4339,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { int appId = UserHandle.getAppId(uid); if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid) && !isUidForegroundOnRestrictPowerUL(uid)) { - setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY); + setUidFirewallRuleUL(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY); if (LOGD) Log.d(TAG, "updateRuleForAppIdleUL DENY " + uid); } else { - setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT); + setUidFirewallRuleUL(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT); if (LOGD) Log.d(TAG, "updateRuleForAppIdleUL " + uid + " to DEFAULT"); } } finally { @@ -5406,10 +5406,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** * Add or remove a uid to the firewall denylist for all network ifaces. */ - private void setUidFirewallRule(int chain, int uid, int rule) { + @GuardedBy("mUidRulesFirstLock") + private void setUidFirewallRuleUL(int chain, int uid, int rule) { if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, - "setUidFirewallRule: " + chain + "/" + uid + "/" + rule); + "setUidFirewallRuleUL: " + chain + "/" + uid + "/" + rule); } try { if (chain == FIREWALL_CHAIN_DOZABLE) { diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java index 30e261725a73..092853f298c2 100644 --- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -39,7 +39,7 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; -import android.telephony.TelephonyManager.CarrierPrivilegesListener; +import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -98,8 +98,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener; @NonNull - private final List<CarrierPrivilegesListener> mCarrierPrivilegesChangedListeners = - new ArrayList<>(); + private final List<CarrierPrivilegesCallback> mCarrierPrivilegesCallbacks = new ArrayList<>(); @NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot; @@ -151,20 +150,21 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { executor, mSubscriptionChangedListener); mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener); - registerCarrierPrivilegesListeners(); + registerCarrierPrivilegesCallbacks(); } - private void registerCarrierPrivilegesListeners() { + // TODO(b/221306368): Refactor with the new onCarrierServiceChange in the new CPCallback + private void registerCarrierPrivilegesCallbacks() { final HandlerExecutor executor = new HandlerExecutor(mHandler); final int modemCount = mTelephonyManager.getActiveModemCount(); try { for (int i = 0; i < modemCount; i++) { - CarrierPrivilegesListener carrierPrivilegesListener = - new CarrierPrivilegesListener() { + CarrierPrivilegesCallback carrierPrivilegesCallback = + new CarrierPrivilegesCallback() { @Override public void onCarrierPrivilegesChanged( - @NonNull List<String> privilegedPackageNames, - @NonNull int[] privilegedUids) { + @NonNull Set<String> privilegedPackageNames, + @NonNull Set<Integer> privilegedUids) { // Re-trigger the synchronous check (which is also very cheap due // to caching in CarrierPrivilegesTracker). This allows consistency // with the onSubscriptionsChangedListener and broadcasts. @@ -172,9 +172,9 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } }; - mTelephonyManager.addCarrierPrivilegesListener( - i, executor, carrierPrivilegesListener); - mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener); + mTelephonyManager.registerCarrierPrivilegesCallback( + i, executor, carrierPrivilegesCallback); + mCarrierPrivilegesCallbacks.add(carrierPrivilegesCallback); } } catch (IllegalArgumentException e) { Slog.wtf(TAG, "Encounted exception registering carrier privileges listeners", e); @@ -191,15 +191,15 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener); mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener); - unregisterCarrierPrivilegesListeners(); + unregisterCarrierPrivilegesCallbacks(); } - private void unregisterCarrierPrivilegesListeners() { - for (CarrierPrivilegesListener carrierPrivilegesListener : - mCarrierPrivilegesChangedListeners) { - mTelephonyManager.removeCarrierPrivilegesListener(carrierPrivilegesListener); + private void unregisterCarrierPrivilegesCallbacks() { + for (CarrierPrivilegesCallback carrierPrivilegesCallback : + mCarrierPrivilegesCallbacks) { + mTelephonyManager.unregisterCarrierPrivilegesCallback(carrierPrivilegesCallback); } - mCarrierPrivilegesChangedListeners.clear(); + mCarrierPrivilegesCallbacks.clear(); } /** @@ -283,7 +283,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } private void handleActionMultiSimConfigChanged(Context context, Intent intent) { - unregisterCarrierPrivilegesListeners(); + unregisterCarrierPrivilegesCallbacks(); // Clear invalid slotIds from the mReadySubIdsBySlotId map. final int modemCount = mTelephonyManager.getActiveModemCount(); @@ -296,7 +296,7 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { } } - registerCarrierPrivilegesListeners(); + registerCarrierPrivilegesCallbacks(); handleSubscriptionsChanged(); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index d69d32effc76..9e87a172101f 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -967,6 +967,26 @@ public class DisplayPolicy { break; } + if (LayoutParams.isSystemAlertWindowType(attrs.type)) { + float maxOpacity = mService.mMaximumObscuringOpacityForTouch; + if (attrs.alpha > maxOpacity + && (attrs.flags & FLAG_NOT_TOUCHABLE) != 0 + && (attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) == 0) { + // The app is posting a SAW with the intent of letting touches pass through, but + // they are going to be deemed untrusted and will be blocked. Try to honor the + // intent of letting touches pass through at the cost of 0.2 opacity for app + // compatibility reasons. More details on b/218777508. + Slog.w(TAG, String.format( + "App %s has a system alert window (type = %d) with FLAG_NOT_TOUCHABLE and " + + "LayoutParams.alpha = %.2f > %.2f, setting alpha to %.2f to " + + "let touches pass through (if this is isn't desirable, remove " + + "flag FLAG_NOT_TOUCHABLE).", + attrs.packageName, attrs.type, attrs.alpha, maxOpacity, maxOpacity)); + attrs.alpha = maxOpacity; + win.mWinAnimator.mAlpha = maxOpacity; + } + } + // Check if alternate bars positions were updated. if (mStatusBarAlt == win) { mStatusBarAltPosition = getAltBarPosition(attrs); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 4258e073429e..40c7b3b81e13 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -769,6 +769,9 @@ public class WindowManagerService extends IWindowManager.Stub private final DisplayHashController mDisplayHashController; + volatile float mMaximumObscuringOpacityForTouch = + InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH; + @VisibleForTesting final WindowContextListenerController mWindowContextListenerController = new WindowContextListenerController(); @@ -801,6 +804,8 @@ public class WindowManagerService extends IWindowManager.Stub DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR); private final Uri mDisplaySettingsPathUri = Settings.Global.getUriFor( DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH); + private final Uri mMaximumObscuringOpacityForTouchUri = Settings.Global.getUriFor( + Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH); public SettingsObserver() { super(new Handler()); @@ -827,6 +832,8 @@ public class WindowManagerService extends IWindowManager.Stub UserHandle.USER_ALL); resolver.registerContentObserver(mDisplaySettingsPathUri, false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(mMaximumObscuringOpacityForTouchUri, false, this, + UserHandle.USER_ALL); } @Override @@ -875,6 +882,11 @@ public class WindowManagerService extends IWindowManager.Stub return; } + if (mMaximumObscuringOpacityForTouchUri.equals(uri)) { + updateMaximumObscuringOpacityForTouch(); + return; + } + @UpdateAnimationScaleMode final int mode; if (mWindowAnimationScaleUri.equals(uri)) { @@ -894,6 +906,14 @@ public class WindowManagerService extends IWindowManager.Stub void loadSettings() { updateSystemUiSettings(false /* handleChange */); updatePointerLocation(); + updateMaximumObscuringOpacityForTouch(); + } + + void updateMaximumObscuringOpacityForTouch() { + ContentResolver resolver = mContext.getContentResolver(); + mMaximumObscuringOpacityForTouch = Settings.Global.getFloat(resolver, + Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH, + InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH); } void updateSystemUiSettings(boolean handleChange) { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java index 66da2a631868..716612c70aef 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java @@ -284,7 +284,7 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase { .setCreateActivity(true).build().getTopMostActivity(); activity2.getTask().setResumedActivity(activity2, "test"); - mAtm.mAmInternal.deletePendingTopUid(activity1.getUid()); + mAtm.mAmInternal.deletePendingTopUid(activity1.getUid(), Long.MAX_VALUE); clearInvocations(mAtm); activity1.moveFocusableActivityToTop("test"); assertTrue(mAtm.mAmInternal.isPendingTopUid(activity1.getUid())); diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java index fcbb008c79b3..7d857a2dc1b4 100644 --- a/telephony/java/android/service/euicc/EuiccService.java +++ b/telephony/java/android/service/euicc/EuiccService.java @@ -255,6 +255,12 @@ public abstract class EuiccService extends Service { public static final String EXTRA_RESOLUTION_CARD_ID = "android.service.euicc.extra.RESOLUTION_CARD_ID"; + /** + * Intent extra set for resolution requests containing an int indicating the current port index. + */ + public static final String EXTRA_RESOLUTION_PORT_INDEX = + "android.service.euicc.extra.RESOLUTION_PORT_INDEX"; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "RESULT_" }, value = { @@ -579,9 +585,32 @@ public abstract class EuiccService extends Service { * @return the result of the switch operation. May be one of the predefined {@code RESULT_} * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. * @see android.telephony.euicc.EuiccManager#switchToSubscription + * + * @deprecated prefer {@link #onSwitchToSubscriptionWithPort(int, int, String, boolean)} */ - public abstract @Result int onSwitchToSubscription(int slotId, @Nullable String iccid, - boolean forceDeactivateSim); + @Deprecated public abstract @Result int onSwitchToSubscription(int slotId, + @Nullable String iccid, boolean forceDeactivateSim); + + /** + * Switch to the given subscription. + * + * @param slotId ID of the SIM slot to use for the operation. + * @param portIndex which port on the eUICC to use + * @param iccid the ICCID of the subscription to enable. May be null, in which case the current + * profile should be deactivated and no profile should be activated to replace it - this is + * equivalent to a physical SIM being ejected. + * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the + * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} + * should be returned to allow the user to consent to this operation first. + * @return the result of the switch operation. May be one of the predefined {@code RESULT_} + * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. + * @see android.telephony.euicc.EuiccManager#switchToSubscription + */ + public @Result int onSwitchToSubscriptionWithPort(int slotId, int portIndex, + @Nullable String iccid, boolean forceDeactivateSim) { + // stub implementation, LPA needs to implement this + throw new UnsupportedOperationException("LPA must override onSwitchToSubscriptionWithPort"); + } /** * Update the nickname of the given subscription. @@ -821,16 +850,15 @@ public abstract class EuiccService extends Service { } }); } - @Override - public void switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim, - ISwitchToSubscriptionCallback callback) { + public void switchToSubscription(int slotId, int portIndex, String iccid, + boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback) { mExecutor.execute(new Runnable() { @Override public void run() { int result = - EuiccService.this.onSwitchToSubscription( - slotId, iccid, forceDeactivateSim); + EuiccService.this.onSwitchToSubscriptionWithPort( + slotId, portIndex, iccid, forceDeactivateSim); try { callback.onComplete(result); } catch (RemoteException e) { diff --git a/telephony/java/android/service/euicc/IEuiccService.aidl b/telephony/java/android/service/euicc/IEuiccService.aidl index bb7b569f17f9..aa30c9e88462 100644 --- a/telephony/java/android/service/euicc/IEuiccService.aidl +++ b/telephony/java/android/service/euicc/IEuiccService.aidl @@ -48,7 +48,7 @@ oneway interface IEuiccService { in IGetDefaultDownloadableSubscriptionListCallback callback); void getEuiccInfo(int slotId, in IGetEuiccInfoCallback callback); void deleteSubscription(int slotId, String iccid, in IDeleteSubscriptionCallback callback); - void switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim, + void switchToSubscription(int slotId, int portIndex, String iccid, boolean forceDeactivateSim, in ISwitchToSubscriptionCallback callback); void updateSubscriptionNickname(int slotId, String iccid, String nickname, in IUpdateSubscriptionNicknameCallback callback); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index c66229875ee2..db1f49760865 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -6776,10 +6776,12 @@ public class TelephonyManager { * @param p2 P2 parameter (described in ISO 7816-4). * @return an IccOpenLogicalChannelResponse object. * @hide + * @deprecated instead use {@link #iccOpenLogicalChannelByPort(int, int, String, int)} */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi @Nullable + @Deprecated public IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int slotIndex, @Nullable String aid, int p2) { try { @@ -6800,6 +6802,58 @@ public class TelephonyManager { } /** + * Opens a logical channel to the ICC card using the physical slot index and port index. + * + * Use this method when no subscriptions are available on the SIM and the operation must be + * performed using the physical slot index and port index. + * + * This operation wraps two APDU instructions: + * <ul> + * <li>MANAGE CHANNEL to open a logical channel</li> + * <li>SELECT the given {@code AID} using the given {@code p2}</li> + * </ul> + * + * Per Open Mobile API Specification v3.2 section 6.2.7.h, only p2 values of 0x00, 0x04, 0x08, + * and 0x0C are guaranteed to be supported. + * + * If the SELECT command's status word is not '9000', '62xx', or '63xx', the status word will be + * considered an error and the channel shall not be opened. + * + * Input parameters equivalent to TS 27.007 AT+CCHO command. + * + * @param slotIndex the physical slot index of the ICC card + * @param portIndex The port index is an enumeration of the ports available on the UICC. + * Use {@link UiccPortInfo#getPortIndex()} to get portIndex. + * @param aid Application id. See ETSI 102.221 and 101.220. + * @param p2 P2 parameter (described in ISO 7816-4). + * @return an IccOpenLogicalChannelResponse object. + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @SystemApi + @NonNull + public IccOpenLogicalChannelResponse iccOpenLogicalChannelByPort(int slotIndex, + int portIndex, @Nullable String aid, int p2) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + IccLogicalChannelRequest request = new IccLogicalChannelRequest(); + request.slotIndex = slotIndex; + request.portIndex = portIndex; + request.aid = aid; + request.p2 = p2; + request.callingPackage = getOpPackageName(); + request.binder = new Binder(); + return telephony.iccOpenLogicalChannel(request); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + throw ex.rethrowAsRuntimeException(); + } + } + + /** * Opens a logical channel to the ICC card. * * This operation wraps two APDU instructions: @@ -6889,9 +6943,11 @@ public class TelephonyManager { * iccOpenLogicalChannel. * @return true if the channel was closed successfully. * @hide + * @deprecated instead use {@link #iccCloseLogicalChannelByPort(int, int, int)} */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi + @Deprecated public boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel) { try { ITelephony telephony = getITelephony(); @@ -6908,6 +6964,45 @@ public class TelephonyManager { } /** + * Closes a previously opened logical channel to the ICC card using the physical slot index and + * port index. + * + * Use this method when no subscriptions are available on the SIM and the operation must be + * performed using the physical slot index and port index. + * + * Input parameters equivalent to TS 27.007 AT+CCHC command. + * + * @param slotIndex the physical slot index of the ICC card + * @param portIndex The port index is an enumeration of the ports available on the UICC. + * Use {@link UiccPortInfo#getPortIndex()} to get portIndex. + * @param channel is the channel id to be closed as returned by a successful + * iccOpenLogicalChannel. + * + * @throws IllegalStateException if the Telephony process is not currently available or modem + * currently can't process this command. + * @throws IllegalArgumentException if invalid arguments are passed. + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @SystemApi + public void iccCloseLogicalChannelByPort(int slotIndex, int portIndex, int channel) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + IccLogicalChannelRequest request = new IccLogicalChannelRequest(); + request.slotIndex = slotIndex; + request.portIndex = portIndex; + request.channel = channel; + telephony.iccCloseLogicalChannel(request); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + throw ex.rethrowAsRuntimeException(); + } + } + + /** * Closes a previously opened logical channel to the ICC card. * * Input parameters equivalent to TS 27.007 AT+CCHC command. @@ -6978,10 +7073,13 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at the end, or null if * there is an issue connecting to the Telephony service. * @hide + * @deprecated instead use + * {@link #iccTransmitApduLogicalChannelByPort(int, int, int, int, int, int, int, int, String)} */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi @Nullable + @Deprecated public String iccTransmitApduLogicalChannelBySlot(int slotIndex, int channel, int cla, int instruction, int p1, int p2, int p3, @Nullable String data) { try { @@ -6997,6 +7095,50 @@ public class TelephonyManager { } /** + * Transmit an APDU to the ICC card over a logical channel using the physical slot index. + * + * Use this method when no subscriptions are available on the SIM and the operation must be + * performed using the physical slot index. + * + * Input parameters equivalent to TS 27.007 AT+CGLA command. + * + * @param slotIndex the physical slot index of the ICC card + * @param portIndex The port index is an enumeration of the ports available on the UICC. + * Use {@link UiccPortInfo#getPortIndex()} to get portIndex. + * @param channel is the channel id to be closed as returned by a successful + * iccOpenLogicalChannel. + * @param cla Class of the APDU command. + * @param instruction Instruction of the APDU command. + * @param p1 P1 value of the APDU command. + * @param p2 P2 value of the APDU command. + * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU + * is sent to the SIM. + * @param data Data to be sent with the APDU. + * @return The APDU response from the ICC card with the status appended at the end, or null if + * there is an issue connecting to the Telephony service. + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @SystemApi + @NonNull + public String iccTransmitApduLogicalChannelByPort(int slotIndex, int portIndex, int channel, + int cla, int instruction, int p1, int p2, int p3, @Nullable String data) { + String response; + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + response = telephony.iccTransmitApduLogicalChannelByPort(slotIndex, portIndex, + channel, cla, instruction, p1, p2, p3, data); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + throw ex.rethrowAsRuntimeException(); + } + return response; + } + + /** * Transmit an APDU to the ICC card over a logical channel. * * Input parameters equivalent to TS 27.007 AT+CGLA command. @@ -7081,10 +7223,13 @@ public class TelephonyManager { * @return The APDU response from the ICC card with the status appended at * the end. * @hide + * @deprecated instead use + * {@link #iccTransmitApduBasicChannelByPort(int, int, int, int, int, int, int, String)} */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi @NonNull + @Deprecated public String iccTransmitApduBasicChannelBySlot(int slotIndex, int cla, int instruction, int p1, int p2, int p3, @Nullable String data) { try { @@ -7100,6 +7245,47 @@ public class TelephonyManager { } /** + * Transmit an APDU to the ICC card over the basic channel using the physical slot index. + * + * Use this method when no subscriptions are available on the SIM and the operation must be + * performed using the physical slot index. + * + * Input parameters equivalent to TS 27.007 AT+CSIM command. + * + * @param slotIndex the physical slot index of the ICC card to target + * @param portIndex The port index is an enumeration of the ports available on the UICC. + * Use {@link UiccPortInfo#getPortIndex()} to get portIndex. + * @param cla Class of the APDU command. + * @param instruction Instruction of the APDU command. + * @param p1 P1 value of the APDU command. + * @param p2 P2 value of the APDU command. + * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU + * is sent to the SIM. + * @param data Data to be sent with the APDU. + * @return The APDU response from the ICC card with the status appended at + * the end. + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @SystemApi + @NonNull + public String iccTransmitApduBasicChannelByPort(int slotIndex, int portIndex, int cla, + int instruction, int p1, int p2, int p3, @Nullable String data) { + String response; + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + response = telephony.iccTransmitApduBasicChannelByPort(slotIndex, portIndex, + getOpPackageName(), cla, instruction, p1, p2, p3, data); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + throw ex.rethrowAsRuntimeException(); + } + return response; + } + /** * Transmit an APDU to the ICC card over the basic channel. * * Input parameters equivalent to TS 27.007 AT+CSIM command. @@ -9417,15 +9603,7 @@ public class TelephonyManager { @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public @Nullable String getCarrierServicePackageName() { - // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the - // value instead of re-querying every time. - List<String> carrierServicePackages = - getCarrierPackageNamesForIntent( - new Intent(CarrierService.CARRIER_SERVICE_INTERFACE)); - if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) { - return carrierServicePackages.get(0); - } - return null; + return getCarrierServicePackageNameForLogicalSlot(getPhoneId()); } /** @@ -9442,13 +9620,15 @@ public class TelephonyManager { @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public @Nullable String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) { - // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the - // value instead of re-querying every time. - List<String> carrierServicePackages = - getCarrierPackageNamesForIntentAndPhone( - new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), logicalSlotIndex); - if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) { - return carrierServicePackages.get(0); + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getCarrierServicePackageNameForLogicalSlot(logicalSlotIndex); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "getCarrierServicePackageNameForLogicalSlot RemoteException", ex); + } catch (NullPointerException ex) { + Rlog.e(TAG, "getCarrierServicePackageNameForLogicalSlot NPE", ex); } return null; } @@ -16246,31 +16426,6 @@ public class TelephonyManager { } /** - * Callback to listen for when the set of packages with carrier privileges for a SIM changes. - * - * @hide - * @deprecated Use {@link CarrierPrivilegesCallback} instead. This API will be removed soon - * prior to API finalization. - */ - @SystemApi - public interface CarrierPrivilegesListener { - /** - * Called when the set of packages with carrier privileges has changed. - * - * <p>Of note, this callback will <b>not</b> be fired if a carrier triggers a SIM profile - * switch and the same set of packages remains privileged after the switch. - * - * <p>At registration, the callback will receive the current set of privileged packages. - * - * @param privilegedPackageNames The updated set of package names that have carrier - * privileges - * @param privilegedUids The updated set of UIDs that have carrier privileges - */ - void onCarrierPrivilegesChanged( - @NonNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids); - } - - /** * Callbacks to listen for when the set of packages with carrier privileges for a SIM changes. * * <p>Of note, when multiple callbacks are registered, they may be triggered one after another. @@ -16319,89 +16474,51 @@ public class TelephonyManager { } /** - * Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to + * Registers a {@link CarrierPrivilegesCallback} on the given {@code logicalSlotIndex} to * receive callbacks when the set of packages with carrier privileges changes. The callback will * immediately be called with the latest state. * * @param logicalSlotIndex The SIM slot to listen on - * @param executor The executor where {@code listener} will be invoked - * @param listener The callback to register + * @param executor The executor where {@code callback} will be invoked + * @param callback The callback to register * @hide - * @deprecated Use {@link #registerCarrierPrivilegesCallback} instead. This API will be - * removed prior to API finalization. */ - @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void addCarrierPrivilegesListener( + public void registerCarrierPrivilegesCallback( int logicalSlotIndex, @NonNull @CallbackExecutor Executor executor, - @NonNull CarrierPrivilegesListener listener) { + @NonNull CarrierPrivilegesCallback callback) { if (mContext == null) { throw new IllegalStateException("Telephony service is null"); - } else if (executor == null || listener == null) { + } else if (executor == null || callback == null) { throw new IllegalArgumentException( - "CarrierPrivilegesListener and executor must be non-null"); + "CarrierPrivilegesCallback and executor must be non-null"); } mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class); if (mTelephonyRegistryMgr == null) { throw new IllegalStateException("Telephony registry service is null"); } - mTelephonyRegistryMgr.addCarrierPrivilegesListener(logicalSlotIndex, executor, listener); + mTelephonyRegistryMgr.addCarrierPrivilegesCallback(logicalSlotIndex, executor, callback); } /** - * Unregisters an existing {@link CarrierPrivilegesListener}. + * Unregisters an existing {@link CarrierPrivilegesCallback}. * * @hide - * @deprecated Use {@link #unregisterCarrierPrivilegesCallback} instead. This API will be - * removed prior to API finalization. */ - @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) { + public void unregisterCarrierPrivilegesCallback(@NonNull CarrierPrivilegesCallback callback) { if (mContext == null) { throw new IllegalStateException("Telephony service is null"); - } else if (listener == null) { - throw new IllegalArgumentException("CarrierPrivilegesListener must be non-null"); + } else if (callback == null) { + throw new IllegalArgumentException("CarrierPrivilegesCallback must be non-null"); } mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class); if (mTelephonyRegistryMgr == null) { throw new IllegalStateException("Telephony registry service is null"); } - mTelephonyRegistryMgr.removeCarrierPrivilegesListener(listener); - } - - /** - * Registers a {@link CarrierPrivilegesCallback} on the given {@code logicalSlotIndex} to - * receive callbacks when the set of packages with carrier privileges changes. The callback will - * immediately be called with the latest state. - * - * @param logicalSlotIndex The SIM slot to listen on - * @param executor The executor where {@code callback} will be invoked - * @param callback The callback to register - * @hide - */ - @SystemApi - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void registerCarrierPrivilegesCallback( - int logicalSlotIndex, - @NonNull @CallbackExecutor Executor executor, - @NonNull CarrierPrivilegesCallback callback) { - // TODO(b/216549778): cherry-pick implementation once merge conflict is resolved - throw new UnsupportedOperationException("Not implemented, yet"); - } - - /** - * Unregisters an existing {@link CarrierPrivilegesCallback}. - * - * @hide - */ - @SystemApi - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void unregisterCarrierPrivilegesCallback(@NonNull CarrierPrivilegesCallback callback) { - // TODO(b/216549778): cherry-pick implementation once merge conflict is resolved - throw new UnsupportedOperationException("Not implemented, yet"); + mTelephonyRegistryMgr.removeCarrierPrivilegesCallback(callback); } } diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index 45022a6e4d8c..aa514b99dad3 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -16,6 +16,7 @@ package android.telephony.euicc; import android.Manifest; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -28,6 +29,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager; +import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; import android.telephony.TelephonyFrameworkInitializer; @@ -35,11 +37,13 @@ import android.telephony.TelephonyManager; import android.telephony.euicc.EuiccCardManager.ResetOption; import com.android.internal.telephony.euicc.IEuiccController; +import com.android.internal.telephony.euicc.IResultCallback; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collections; import java.util.List; +import java.util.concurrent.Executor; import java.util.stream.Collectors; /** @@ -215,6 +219,20 @@ public class EuiccManager { "android.telephony.euicc.action.START_EUICC_ACTIVATION"; /** + * Result codes passed to the ResultListener by + * {@link #switchToSubscription(int, int, Executor, ResultListener)} + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"EMBEDDED_SUBSCRIPTION_RESULT_"}, value = { + EMBEDDED_SUBSCRIPTION_RESULT_OK, + EMBEDDED_SUBSCRIPTION_RESULT_ERROR, + EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR + }) + public @interface ResultCode{} + + /** * Result code for an operation indicating that the operation succeeded. */ public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0; @@ -1125,7 +1143,12 @@ public class EuiccManager { * permission, or the calling app must be authorized to manage the active subscription on * the target eUICC. * @param callbackIntent a PendingIntent to launch when the operation completes. + * + * @deprecated From T, callers should use + * {@link #switchToSubscription(int, int, Executor, ResultListener)} instead to specify a port + * index on the card to switch to. */ + @Deprecated @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) { if (!isEnabled()) { @@ -1141,6 +1164,71 @@ public class EuiccManager { } /** + * Switch to (enable) the given subscription. + * + * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, + * or the calling app must be authorized to manage both the currently-active subscription and + * the subscription to be enabled according to the subscription metadata. Without the former, + * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback + * intent to prompt the user to accept the download. + * + * <p>On a multi-active SIM device, requires the + * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, or a calling app + * only if the targeted eUICC does not currently have an active subscription or the calling app + * is authorized to manage the active subscription on the target eUICC, and the calling app is + * authorized to manage any active subscription on any SIM. Without it, an + * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback + * intent to prompt the user to accept the download. The caller should also be authorized to + * manage the subscription to be enabled. + * + * @param subscriptionId the ID of the subscription to enable. May be + * {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID} to deactivate the + * current profile without activating another profile to replace it. If it's a disable + * operation, requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} + * permission, or the calling app must be authorized to manage the active subscription on + * the target eUICC. + * @param portIndex the index of the port to target for the enabled subscription + * @param executor an Executor on which to run the callback + * @param callback a {@link ResultListener} which will run when the operation completes + */ + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) + public void switchToSubscription(int subscriptionId, int portIndex, + @NonNull @CallbackExecutor Executor executor, + @NonNull ResultListener callback) { + if (!isEnabled()) { + sendUnavailableErrorToCallback(executor, callback); + return; + } + try { + IResultCallback internalCallback = new IResultCallback.Stub() { + @Override + public void onComplete(int result, Intent resultIntent) { + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> callback.onComplete(result, resultIntent))); + } + }; + getIEuiccController().switchToSubscriptionWithPort(mCardId, portIndex, + subscriptionId, mContext.getOpPackageName(), internalCallback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Callback to receive the result of an EuiccManager API. + */ + public interface ResultListener { + /** + * Called on completion of some operation. + * @param resultCode representing success or specific failure of the operation + * (See {@link ResultCode}) + * @param resultIntent an intent used to start a resolution activity when an error + * occurs that can be resolved by the user + */ + void onComplete(@ResultCode int resultCode, @Nullable Intent resultIntent); + } + + /** * Update the nickname for the given subscription. * * <p>Requires that the calling app has carrier privileges according to the metadata of the @@ -1411,6 +1499,13 @@ public class EuiccManager { } } + private static void sendUnavailableErrorToCallback(@NonNull Executor executor, + ResultListener callback) { + Integer result = EMBEDDED_SUBSCRIPTION_RESULT_ERROR; + executor.execute(() -> + Binder.withCleanCallingIdentity(() -> callback.onComplete(result, null))); + } + private static IEuiccController getIEuiccController() { return IEuiccController.Stub.asInterface( TelephonyFrameworkInitializer diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index b56aa9687aee..f5b158fedd37 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -375,12 +375,16 @@ public abstract class ImsFeature { */ @SystemApi public final void setFeatureState(@ImsState int state) { + boolean isNotify = false; synchronized (mLock) { if (mState != state) { mState = state; - notifyFeatureState(state); + isNotify = true; } } + if (isNotify) { + notifyFeatureState(state); + } } /** @@ -412,14 +416,16 @@ public abstract class ImsFeature { * Internal method called by ImsFeature when setFeatureState has changed. */ private void notifyFeatureState(@ImsState int state) { - mStatusCallbacks.broadcastAction((c) -> { - try { - c.notifyImsFeatureStatus(state); - } catch (RemoteException e) { - Log.w(LOG_TAG, e + " notifyFeatureState() - Skipping " - + "callback."); - } - }); + synchronized (mStatusCallbacks) { + mStatusCallbacks.broadcastAction((c) -> { + try { + c.notifyImsFeatureStatus(state); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + " notifyFeatureState() - Skipping " + + "callback."); + } + }); + } } /** @@ -491,14 +497,19 @@ public abstract class ImsFeature { synchronized (mLock) { mCapabilityStatus = caps.copy(); } - mCapabilityCallbacks.broadcastAction((callback) -> { - try { - callback.onCapabilitiesStatusChanged(caps.mCapabilities); - } catch (RemoteException e) { - Log.w(LOG_TAG, e + " notifyCapabilitiesStatusChanged() - Skipping " - + "callback."); - } - }); + + synchronized (mCapabilityCallbacks) { + mCapabilityCallbacks.broadcastAction((callback) -> { + try { + Log.d(LOG_TAG, "ImsFeature notifyCapabilitiesStatusChanged Capabilities = " + + caps.mCapabilities); + callback.onCapabilitiesStatusChanged(caps.mCapabilities); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + " notifyCapabilitiesStatusChanged() - Skipping " + + "callback."); + } + }); + } } /** diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java index 11fc328a42c7..f371ec3a28a7 100644 --- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java @@ -587,13 +587,15 @@ public class ImsConfigImplBase { if (mCallbacks == null) { return; } - mCallbacks.broadcastAction(c -> { - try { - c.onIntConfigChanged(item, value); - } catch (RemoteException e) { - Log.w(TAG, "notifyConfigChanged(int): dead binder in notify, skipping."); - } - }); + synchronized (mCallbacks) { + mCallbacks.broadcastAction(c -> { + try { + c.onIntConfigChanged(item, value); + } catch (RemoteException e) { + Log.w(TAG, "notifyConfigChanged(int): dead binder in notify, skipping."); + } + }); + } } private void notifyConfigChanged(int item, String value) { @@ -601,13 +603,15 @@ public class ImsConfigImplBase { if (mCallbacks == null) { return; } - mCallbacks.broadcastAction(c -> { - try { - c.onStringConfigChanged(item, value); - } catch (RemoteException e) { - Log.w(TAG, "notifyConfigChanged(string): dead binder in notify, skipping."); - } - }); + synchronized (mCallbacks) { + mCallbacks.broadcastAction(c -> { + try { + c.onStringConfigChanged(item, value); + } catch (RemoteException e) { + Log.w(TAG, "notifyConfigChanged(string): dead binder in notify, skipping."); + } + }); + } } private void addRcsConfigCallback(IRcsConfigCallback c) { @@ -635,13 +639,15 @@ public class ImsConfigImplBase { // can be null in testing if (mRcsCallbacks != null) { - mRcsCallbacks.broadcastAction(c -> { - try { - c.onConfigurationChanged(mRcsConfigData); - } catch (RemoteException e) { - Log.w(TAG, "dead binder in notifyRcsAutoConfigurationReceived, skipping."); - } - }); + synchronized (mRcsCallbacks) { + mRcsCallbacks.broadcastAction(c -> { + try { + c.onConfigurationChanged(mRcsConfigData); + } catch (RemoteException e) { + Log.w(TAG, "dead binder in notifyRcsAutoConfigurationReceived, skipping."); + } + }); + } } notifyRcsAutoConfigurationReceived(config, isCompressed); } @@ -649,13 +655,15 @@ public class ImsConfigImplBase { private void onNotifyRcsAutoConfigurationRemoved() { mRcsConfigData = null; if (mRcsCallbacks != null) { - mRcsCallbacks.broadcastAction(c -> { - try { - c.onConfigurationReset(); - } catch (RemoteException e) { - Log.w(TAG, "dead binder in notifyRcsAutoConfigurationRemoved, skipping."); - } - }); + synchronized (mRcsCallbacks) { + mRcsCallbacks.broadcastAction(c -> { + try { + c.onConfigurationReset(); + } catch (RemoteException e) { + Log.w(TAG, "dead binder in notifyRcsAutoConfigurationRemoved, skipping."); + } + }); + } } notifyRcsAutoConfigurationRemoved(); } @@ -801,13 +809,15 @@ public class ImsConfigImplBase { if (mRcsCallbacks == null) { return; } - mRcsCallbacks.broadcastAction(c -> { - try { - c.onAutoConfigurationErrorReceived(errorCode, errorString); - } catch (RemoteException e) { - Log.w(TAG, "dead binder in notifyAutoConfigurationErrorReceived, skipping."); - } - }); + synchronized (mRcsCallbacks) { + mRcsCallbacks.broadcastAction(c -> { + try { + c.onAutoConfigurationErrorReceived(errorCode, errorString); + } catch (RemoteException e) { + Log.w(TAG, "dead binder in notifyAutoConfigurationErrorReceived, skipping."); + } + }); + } } /** @@ -825,13 +835,15 @@ public class ImsConfigImplBase { if (mRcsCallbacks == null) { return; } - mRcsCallbacks.broadcastAction(c -> { - try { - c.onPreProvisioningReceived(configXml); - } catch (RemoteException e) { - Log.w(TAG, "dead binder in notifyPreProvisioningReceived, skipping."); - } - }); + synchronized (mRcsCallbacks) { + mRcsCallbacks.broadcastAction(c -> { + try { + c.onPreProvisioningReceived(configXml); + } catch (RemoteException e) { + Log.w(TAG, "dead binder in notifyPreProvisioningReceived, skipping."); + } + }); + } } /** diff --git a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java index 2783e299236b..fb997d118419 100644 --- a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java @@ -219,22 +219,25 @@ public class ImsSmsImplBase { */ public final void onSmsReceived(int token, @SmsMessage.Format String format, byte[] pdu) throws RuntimeException { + IImsSmsListener listener = null; synchronized (mLock) { - if (mListener == null) { - throw new RuntimeException("Feature not ready."); - } - try { - mListener.onSmsReceived(token, format, pdu); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage()); - SmsMessage message = SmsMessage.createFromPdu(pdu, format); - if (message != null && message.mWrappedSmsMessage != null) { - acknowledgeSms(token, message.mWrappedSmsMessage.mMessageRef, - DELIVER_STATUS_ERROR_GENERIC); - } else { - Log.w(LOG_TAG, "onSmsReceived: Invalid pdu entered."); - acknowledgeSms(token, 0, DELIVER_STATUS_ERROR_GENERIC); - } + listener = mListener; + } + + if (listener == null) { + throw new RuntimeException("Feature not ready."); + } + try { + listener.onSmsReceived(token, format, pdu); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage()); + SmsMessage message = SmsMessage.createFromPdu(pdu, format); + if (message != null && message.mWrappedSmsMessage != null) { + acknowledgeSms(token, message.mWrappedSmsMessage.mMessageRef, + DELIVER_STATUS_ERROR_GENERIC); + } else { + Log.w(LOG_TAG, "onSmsReceived: Invalid pdu entered."); + acknowledgeSms(token, 0, DELIVER_STATUS_ERROR_GENERIC); } } } @@ -254,16 +257,19 @@ public class ImsSmsImplBase { */ public final void onSendSmsResultSuccess(int token, @IntRange(from = 0, to = 65535) int messageRef) throws RuntimeException { + IImsSmsListener listener = null; synchronized (mLock) { - if (mListener == null) { - throw new RuntimeException("Feature not ready."); - } - try { - mListener.onSendSmsResult(token, messageRef, SEND_STATUS_OK, - SmsManager.RESULT_ERROR_NONE, RESULT_NO_NETWORK_ERROR); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } + listener = mListener; + } + + if (listener == null) { + throw new RuntimeException("Feature not ready."); + } + try { + listener.onSendSmsResult(token, messageRef, SEND_STATUS_OK, + SmsManager.RESULT_ERROR_NONE, RESULT_NO_NETWORK_ERROR); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); } } @@ -288,16 +294,19 @@ public class ImsSmsImplBase { @Deprecated public final void onSendSmsResult(int token, @IntRange(from = 0, to = 65535) int messageRef, @SendStatusResult int status, @SmsManager.Result int reason) throws RuntimeException { + IImsSmsListener listener = null; synchronized (mLock) { - if (mListener == null) { - throw new RuntimeException("Feature not ready."); - } - try { - mListener.onSendSmsResult(token, messageRef, status, reason, - RESULT_NO_NETWORK_ERROR); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } + listener = mListener; + } + + if (listener == null) { + throw new RuntimeException("Feature not ready."); + } + try { + listener.onSendSmsResult(token, messageRef, status, reason, + RESULT_NO_NETWORK_ERROR); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); } } @@ -322,15 +331,18 @@ public class ImsSmsImplBase { public final void onSendSmsResultError(int token, @IntRange(from = 0, to = 65535) int messageRef, @SendStatusResult int status, @SmsManager.Result int reason, int networkErrorCode) throws RuntimeException { + IImsSmsListener listener = null; synchronized (mLock) { - if (mListener == null) { - throw new RuntimeException("Feature not ready."); - } - try { - mListener.onSendSmsResult(token, messageRef, status, reason, networkErrorCode); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } + listener = mListener; + } + + if (listener == null) { + throw new RuntimeException("Feature not ready."); + } + try { + listener.onSendSmsResult(token, messageRef, status, reason, networkErrorCode); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); } } @@ -357,16 +369,19 @@ public class ImsSmsImplBase { public final void onSmsStatusReportReceived(int token, @IntRange(from = 0, to = 65535) int messageRef, @SmsMessage.Format String format, byte[] pdu) throws RuntimeException { + IImsSmsListener listener = null; synchronized (mLock) { - if (mListener == null) { - throw new RuntimeException("Feature not ready."); - } - try { - mListener.onSmsStatusReportReceived(token, format, pdu); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage()); - acknowledgeSmsReport(token, messageRef, STATUS_REPORT_STATUS_ERROR); - } + listener = mListener; + } + + if (listener == null) { + throw new RuntimeException("Feature not ready."); + } + try { + listener.onSmsStatusReportReceived(token, format, pdu); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage()); + acknowledgeSmsReport(token, messageRef, STATUS_REPORT_STATUS_ERROR); } } @@ -386,24 +401,27 @@ public class ImsSmsImplBase { */ public final void onSmsStatusReportReceived(int token, @SmsMessage.Format String format, byte[] pdu) throws RuntimeException { + IImsSmsListener listener = null; synchronized (mLock) { - if (mListener == null) { - throw new RuntimeException("Feature not ready."); - } - try { - mListener.onSmsStatusReportReceived(token, format, pdu); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage()); - SmsMessage message = SmsMessage.createFromPdu(pdu, format); - if (message != null && message.mWrappedSmsMessage != null) { - acknowledgeSmsReport( - token, - message.mWrappedSmsMessage.mMessageRef, - STATUS_REPORT_STATUS_ERROR); - } else { - Log.w(LOG_TAG, "onSmsStatusReportReceived: Invalid pdu entered."); - acknowledgeSmsReport(token, 0, STATUS_REPORT_STATUS_ERROR); - } + listener = mListener; + } + + if (listener == null) { + throw new RuntimeException("Feature not ready."); + } + try { + listener.onSmsStatusReportReceived(token, format, pdu); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage()); + SmsMessage message = SmsMessage.createFromPdu(pdu, format); + if (message != null && message.mWrappedSmsMessage != null) { + acknowledgeSmsReport( + token, + message.mWrappedSmsMessage.mMessageRef, + STATUS_REPORT_STATUS_ERROR); + } else { + Log.w(LOG_TAG, "onSmsStatusReportReceived: Invalid pdu entered."); + acknowledgeSmsReport(token, 0, STATUS_REPORT_STATUS_ERROR); } } } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 0d8881b4349b..883e2ad9b76e 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2545,4 +2545,15 @@ interface ITelephony { * registration technology specified, false if it is not required. */ boolean isRcsProvisioningRequiredForCapability(int subId, int capability, int tech); + + /** + * Returns the package name that provides the {@link CarrierService} implementation for the + * specified {@code logicalSlotIndex}, or {@code null} if no package with carrier privileges + * declares one. + * + * @param logicalSlotIndex The slot index to fetch the {@link CarrierService} package for + * @return The system-selected package that provides the {@link CarrierService} implementation + * for the slot, or {@code null} if none is resolved + */ + String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex); } diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl index 944ce3486ca6..7f5982f128e3 100644 --- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl +++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl @@ -21,6 +21,9 @@ import android.content.Intent; import android.os.Bundle; import android.telephony.euicc.DownloadableSubscription; import android.telephony.euicc.EuiccInfo; + +import com.android.internal.telephony.euicc.IResultCallback; + import java.util.List; /** @hide */ @@ -42,6 +45,8 @@ interface IEuiccController { in PendingIntent callbackIntent); oneway void switchToSubscription(int cardId, int subscriptionId, String callingPackage, in PendingIntent callbackIntent); + oneway void switchToSubscriptionWithPort(int cardId, int portIndex, int subscriptionId, + String callingPackage, in IResultCallback callback); oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname, String callingPackage, in PendingIntent callbackIntent); oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent); diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl new file mode 100644 index 000000000000..69f479c683d1 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.euicc; + +import android.content.Intent; + +/** @hide */ +oneway interface IResultCallback { + void onComplete(int resultCode, in Intent resultIntent); +} diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 7b1f7a599519..b67395735426 100644 --- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -60,7 +60,7 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; -import android.telephony.TelephonyManager.CarrierPrivilegesListener; +import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.util.ArrayMap; import android.util.ArraySet; @@ -187,11 +187,11 @@ public class TelephonySubscriptionTrackerTest { return captor.getValue(); } - private List<CarrierPrivilegesListener> getCarrierPrivilegesListeners() { - final ArgumentCaptor<CarrierPrivilegesListener> captor = - ArgumentCaptor.forClass(CarrierPrivilegesListener.class); + private List<CarrierPrivilegesCallback> getCarrierPrivilegesCallbacks() { + final ArgumentCaptor<CarrierPrivilegesCallback> captor = + ArgumentCaptor.forClass(CarrierPrivilegesCallback.class); verify(mTelephonyManager, atLeastOnce()) - .addCarrierPrivilegesListener(anyInt(), any(), captor.capture()); + .registerCarrierPrivilegesCallback(anyInt(), any(), captor.capture()); return captor.getAllValues(); } @@ -270,12 +270,12 @@ public class TelephonySubscriptionTrackerTest { assertNotNull(getOnSubscriptionsChangedListener()); verify(mTelephonyManager, times(2)) - .addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any()); + .registerCarrierPrivilegesCallback(anyInt(), any(HandlerExecutor.class), any()); verify(mTelephonyManager) - .addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any()); + .registerCarrierPrivilegesCallback(eq(0), any(HandlerExecutor.class), any()); verify(mTelephonyManager) - .addCarrierPrivilegesListener(eq(1), any(HandlerExecutor.class), any()); - assertEquals(2, getCarrierPrivilegesListeners().size()); + .registerCarrierPrivilegesCallback(eq(1), any(HandlerExecutor.class), any()); + assertEquals(2, getCarrierPrivilegesCallbacks().size()); } @Test @@ -287,10 +287,10 @@ public class TelephonySubscriptionTrackerTest { final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener(); verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener)); - for (CarrierPrivilegesListener carrierPrivilegesListener : - getCarrierPrivilegesListeners()) { + for (CarrierPrivilegesCallback carrierPrivilegesCallback : + getCarrierPrivilegesCallbacks()) { verify(mTelephonyManager) - .removeCarrierPrivilegesListener(eq(carrierPrivilegesListener)); + .unregisterCarrierPrivilegesCallback(eq(carrierPrivilegesCallback)); } } @@ -303,15 +303,15 @@ public class TelephonySubscriptionTrackerTest { mTelephonySubscriptionTracker.setReadySubIdsBySlotId(readySubIdsBySlotId); doReturn(1).when(mTelephonyManager).getActiveModemCount(); - List<CarrierPrivilegesListener> carrierPrivilegesListeners = - getCarrierPrivilegesListeners(); + List<CarrierPrivilegesCallback> carrierPrivilegesCallbacks = + getCarrierPrivilegesCallbacks(); mTelephonySubscriptionTracker.onReceive(mContext, buildTestMultiSimConfigBroadcastIntent()); mTestLooper.dispatchAll(); - for (CarrierPrivilegesListener carrierPrivilegesListener : carrierPrivilegesListeners) { + for (CarrierPrivilegesCallback carrierPrivilegesCallback : carrierPrivilegesCallbacks) { verify(mTelephonyManager) - .removeCarrierPrivilegesListener(eq(carrierPrivilegesListener)); + .unregisterCarrierPrivilegesCallback(eq(carrierPrivilegesCallback)); } // Expect cache cleared for inactive slots. @@ -323,9 +323,9 @@ public class TelephonySubscriptionTrackerTest { // Expect a new CarrierPrivilegesListener to have been registered for slot 0, and none other // (2 previously registered during startup, for slots 0 & 1) verify(mTelephonyManager, times(3)) - .addCarrierPrivilegesListener(anyInt(), any(HandlerExecutor.class), any()); + .registerCarrierPrivilegesCallback(anyInt(), any(HandlerExecutor.class), any()); verify(mTelephonyManager, times(2)) - .addCarrierPrivilegesListener(eq(0), any(HandlerExecutor.class), any()); + .registerCarrierPrivilegesCallback(eq(0), any(HandlerExecutor.class), any()); // Verify that this triggers a re-evaluation verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); @@ -391,8 +391,8 @@ public class TelephonySubscriptionTrackerTest { public void testOnCarrierPrivilegesChanged() throws Exception { setupReadySubIds(); - final CarrierPrivilegesListener listener = getCarrierPrivilegesListeners().get(0); - listener.onCarrierPrivilegesChanged(Collections.emptyList(), new int[] {}); + final CarrierPrivilegesCallback callback = getCarrierPrivilegesCallbacks().get(0); + callback.onCarrierPrivilegesChanged(Collections.emptySet(), Collections.emptySet()); mTestLooper.dispatchAll(); verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(TEST_PRIVILEGED_PACKAGES))); |