Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit daca795b authored by Jack Yu's avatar Jack Yu
Browse files

Added default voice/data/sms subscription support

Bug: 239607619
Test: atest SubscriptionManagerServiceTest

Merged-In: Ib4a902c73685367edde1a24811c367b0871db683
Change-Id: Ib4a902c73685367edde1a24811c367b0871db683
parent 8e670057
Loading
Loading
Loading
Loading
+291 −54
Original line number Diff line number Diff line
@@ -20,11 +20,13 @@ import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.AppOpsManager;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
@@ -34,9 +36,11 @@ import android.os.Looper;
import android.os.ParcelUuid;
import android.os.TelephonyServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.SubscriptionManager.PhoneNumberSource;
import android.telephony.SubscriptionManager.SubscriptionType;
import android.telephony.TelephonyFrameworkInitializer;
@@ -53,6 +57,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.ISetOpportunisticDataCallback;
import com.android.internal.telephony.ISub;
import com.android.internal.telephony.MultiSimSettingController;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyPermissions;
import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback;
import com.android.internal.telephony.uicc.IccUtils;
@@ -68,6 +73,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -124,8 +130,9 @@ public class SubscriptionManagerService extends ISub.Stub {
    @NonNull
    private final SubscriptionDatabaseManager mSubscriptionDatabaseManager;

    /** The slot index subscription id map. Key is the slot index, and the value is sub id. */
    @NonNull
    private final WatchedSlotIndexToSubId mSlotIndexToSubId = new WatchedSlotIndexToSubId();
    private final WatchedMap<Integer, Integer> mSlotIndexToSubId = new WatchedMap<>();

    /** Subscription manager service callbacks. */
    @NonNull
@@ -133,42 +140,50 @@ public class SubscriptionManagerService extends ISub.Stub {
            new ArraySet<>();

    /**
     * Watched slot index to sub id map.
     * Default sub id. Derived from {@link #mDefaultVoiceSubId} and {@link #mDefaultDataSubId},
     * depending on device capability.
     */
    private static class WatchedSlotIndexToSubId {
        private final Map<Integer, Integer> mSlotIndexToSubId =
                new ConcurrentHashMap<>();
    @NonNull
    private final WatchedInt mDefaultSubId;

        public void clear() {
            mSlotIndexToSubId.clear();
            SubscriptionManager.invalidateDefaultSubIdCaches();
            SubscriptionManager.invalidateSlotIndexCaches();
        }
    /** Default voice subscription id. */
    @NonNull
    private final WatchedInt mDefaultVoiceSubId;

        public Set<Map.Entry<Integer, Integer>> entrySet() {
            return mSlotIndexToSubId.entrySet();
        }
    /** Default data subscription id. */
    @NonNull
    private final WatchedInt mDefaultDataSubId;

        // Force all updates to data structure through wrapper.
        public int get(int slotIndex) {
            return mSlotIndexToSubId.getOrDefault(slotIndex,
                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        }
    /** Default sms subscription id. */
    @NonNull
    private final WatchedInt mDefaultSmsSubId;

        public void put(int slotIndex, int value) {
            mSlotIndexToSubId.put(slotIndex, value);
            SubscriptionManager.invalidateDefaultSubIdCaches();
            SubscriptionManager.invalidateSlotIndexCaches();
    /**
     * Watched map that automatically invalidate cache in {@link SubscriptionManager}.
     */
    private static class WatchedMap<K, V> extends ConcurrentHashMap<K, V> {
        @Override
        public void clear() {
            super.clear();
            SubscriptionManager.invalidateSubscriptionManagerServiceCaches();
        }

        public void remove(int slotIndex) {
            mSlotIndexToSubId.remove(slotIndex);
            SubscriptionManager.invalidateDefaultSubIdCaches();
            SubscriptionManager.invalidateSlotIndexCaches();
        @Override
        public V put(K key, V value) {
            V oldValue = super.put(key, value);
            if (!Objects.equals(oldValue, value)) {
                SubscriptionManager.invalidateSubscriptionManagerServiceCaches();
            }
            return oldValue;
        }

        public int size() {
            return mSlotIndexToSubId.size();
        @Override
        public V remove(Object key) {
            V oldValue = super.remove(key);
            if (oldValue != null) {
                SubscriptionManager.invalidateSubscriptionManagerServiceCaches();
            }
            return oldValue;
        }
    }

@@ -198,9 +213,16 @@ public class SubscriptionManagerService extends ISub.Stub {
         * Set the value.
         *
         * @param newValue The new value.
         *
         * @return {@code true} if {@code newValue} is different from the existing value.
         */
        public void set(int newValue) {
        public boolean set(int newValue) {
            if (mValue != newValue) {
                mValue = newValue;
                SubscriptionManager.invalidateSubscriptionManagerServiceCaches();
                return true;
            }
            return false;
        }
    }

@@ -276,6 +298,50 @@ public class SubscriptionManagerService extends ISub.Stub {
            subscriptionServiceRegisterer.register(this);
        }

        mDefaultVoiceSubId = new WatchedInt(Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
                SubscriptionManager.INVALID_SUBSCRIPTION_ID)) {
            @Override
            public boolean set(int newValue) {
                if (super.set(newValue)) {
                    Settings.Global.putInt(mContext.getContentResolver(),
                            Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, newValue);
                    return true;
                }
                return false;
            }
        };

        mDefaultDataSubId = new WatchedInt(Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION,
                SubscriptionManager.INVALID_SUBSCRIPTION_ID)) {
            @Override
            public boolean set(int newValue) {
                if (super.set(newValue)) {
                    Settings.Global.putInt(mContext.getContentResolver(),
                            Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, newValue);
                    return true;
                }
                return false;
            }
        };

        mDefaultSmsSubId = new WatchedInt(Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION,
                SubscriptionManager.INVALID_SUBSCRIPTION_ID)) {
            @Override
            public boolean set(int newValue) {
                if (super.set(newValue)) {
                    Settings.Global.putInt(mContext.getContentResolver(),
                            Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, newValue);
                    return true;
                }
                return false;
            }
        };

        mDefaultSubId = new WatchedInt(SubscriptionManager.INVALID_SUBSCRIPTION_ID);

        // Create a separate thread for subscription database manager. The database will be updated
        // from a different thread.
        HandlerThread handlerThread = new HandlerThread(LOG_TAG);
@@ -334,6 +400,8 @@ public class SubscriptionManagerService extends ISub.Stub {
                                        () -> callback.onUiccApplicationsEnabled(subId)));
                    }
                });

        updateDefaultSubId();
    }

    /**
@@ -601,24 +669,11 @@ public class SubscriptionManagerService extends ISub.Stub {
     * by {@link SubscriptionInfo#getSimSlotIndex} then by
     * {@link SubscriptionInfo#getSubscriptionId}.
     *
     * @param callingPackage The package making the call
     * @param callingFeatureId The feature in the package
     * @param callingPackage The package making the call.
     * @param callingFeatureId The feature in the package.
     *
     * @return Sorted list of the currently {@link SubscriptionInfo} records available on the
     * device.
     * <ul>
     * <li>
     * If null is returned the current state is unknown but if a
     * {@link OnSubscriptionsChangedListener} has been registered
     * {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be invoked in the future.
     * </li>
     * <li>
     * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
     * </li>
     * <li>
     * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
     * then by {@link SubscriptionInfo#getSubscriptionId}.
     * </li>
     * </ul>
     */
    @Override
    public List<SubscriptionInfo> getActiveSubscriptionInfoList(@NonNull String callingPackage,
@@ -959,11 +1014,35 @@ public class SubscriptionManagerService extends ISub.Stub {
                .collect(Collectors.toList());
    }

    /**
     * Get slot index associated with the subscription.
     *
     * @param subId The subscription id.
     *
     * @return Logical slot indexx (i.e. phone id) as a positive integer or
     * {@link SubscriptionManager#INVALID_SIM_SLOT_INDEX} if the supplied {@code subId} doesn't have
     * an associated slot index.
     */
    @Override
    public int getSlotIndex(int subId) {
        return 0;
        if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
            subId = getDefaultSubId();
        }

        for (Map.Entry<Integer, Integer> entry : mSlotIndexToSubId.entrySet()) {
            if (entry.getValue() == subId) return entry.getKey();
        }

        return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
    }

    /**
     * Get the subscription id for specified slot index.
     *
     * @param slotIndex Logical SIM slot index.
     * @return The subscription id. {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if SIM is
     * absent.
     */
    @Override
    public int getSubId(int slotIndex) {
        if (slotIndex == SubscriptionManager.DEFAULT_SIM_SLOT_INDEX) {
@@ -977,7 +1056,8 @@ public class SubscriptionManagerService extends ISub.Stub {
            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
        }

        return mSlotIndexToSubId.get(slotIndex);
        return mSlotIndexToSubId.getOrDefault(slotIndex,
                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
    }

    @Override
@@ -985,9 +1065,46 @@ public class SubscriptionManagerService extends ISub.Stub {
        return new int[]{getSubId(slotIndex)};
    }

    /**
     * Update default sub id.
     */
    private void updateDefaultSubId() {
        int subId;
        boolean isVoiceCapable = mTelephonyManager.isVoiceCapable();

        if (isVoiceCapable) {
            subId = getDefaultVoiceSubId();
        } else {
            subId = getDefaultDataSubId();
        }

        // If the subId is not active, use the fist active subscription's subId.
        if (!mSlotIndexToSubId.containsValue(subId)) {
            int[] activeSubIds = getActiveSubIdList(true);
            if (activeSubIds.length > 0) {
                subId = activeSubIds[0];
                log("updateDefaultSubId: First available active sub = " + subId);
            } else {
                subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
            }
        }

        if (mDefaultSubId.get() != subId) {
            int phoneId = getPhoneId(subId);
            logl("updateDefaultSubId: Default sub id updated from " + mDefaultSubId.get() + " to "
                    + subId + ", phoneId=" + phoneId);
            mDefaultSubId.set(subId);

            Intent intent = new Intent(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId, subId);
            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
        }
    }

    @Override
    public int getDefaultSubId() {
        return 0;
        return mDefaultSubId.get();
    }

    @Override
@@ -996,6 +1113,7 @@ public class SubscriptionManagerService extends ISub.Stub {
    }

    @Override

    public int getPhoneId(int subId) {
        return 0;
    }
@@ -1007,34 +1125,153 @@ public class SubscriptionManagerService extends ISub.Stub {
     */
    @Override
    public int getDefaultDataSubId() {
        return 0;
        return mDefaultDataSubId.get();
    }

    /**
     * Set the default data subscription id.
     *
     * @param subId The default data subscription id.
     */
    @Override
    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
    public void setDefaultDataSubId(int subId) {
        enforcePermissions("setDefaultDataSubId", Manifest.permission.MODIFY_PHONE_STATE);

        if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
            throw new RuntimeException("setDefaultDataSubId called with DEFAULT_SUBSCRIPTION_ID");
        }

        final long token = Binder.clearCallingIdentity();
        try {
            int oldDefaultDataSubId = mDefaultDataSubId.get();
            if (mDefaultDataSubId.set(subId)) {
                SubscriptionManager.invalidateSubscriptionManagerServiceCaches();
                logl("Default data subId changed from " + oldDefaultDataSubId + " to " + subId);

                MultiSimSettingController.getInstance().notifyDefaultDataSubChanged();

                Intent intent = new Intent(
                        TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
                SubscriptionManager.putSubscriptionIdExtra(intent, subId);
                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);

                updateDefaultSubId();
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override
    public int getDefaultVoiceSubId() {
        return 0;
        return mDefaultVoiceSubId.get();
    }

    /**
     * Set the default voice subscription id.
     *
     * @param subId The default SMS subscription id.
     */
    @Override
    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
    public void setDefaultVoiceSubId(int subId) {
        enforcePermissions("setDefaultVoiceSubId", Manifest.permission.MODIFY_PHONE_STATE);

        if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
            throw new RuntimeException("setDefaultVoiceSubId called with DEFAULT_SUB_ID");
        }

        final long token = Binder.clearCallingIdentity();
        try {
            int oldDefaultVoiceSubId = mDefaultVoiceSubId.get();
            if (mDefaultVoiceSubId.set(subId)) {
                SubscriptionManager.invalidateSubscriptionManagerServiceCaches();
                logl("Default voice subId changed from " + oldDefaultVoiceSubId + " to " + subId);

                Intent intent = new Intent(
                        TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
                SubscriptionManager.putSubscriptionIdExtra(intent, subId);
                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);

                PhoneAccountHandle newHandle = subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
                        ? null : mTelephonyManager.getPhoneAccountHandleForSubscriptionId(subId);

                TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
                if (telecomManager != null) {
                    telecomManager.setUserSelectedOutgoingPhoneAccount(newHandle);
                }

                updateDefaultSubId();
            }

        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override
    public int getDefaultSmsSubId() {
        return 0;
        return mDefaultSmsSubId.get();
    }

    /**
     * Set the default SMS subscription id.
     *
     * @param subId The default SMS subscription id.
     */
    @Override
    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
    public void setDefaultSmsSubId(int subId) {
        enforcePermissions("setDefaultSmsSubId", Manifest.permission.MODIFY_PHONE_STATE);

        if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
            throw new RuntimeException("setDefaultSmsSubId called with DEFAULT_SUB_ID");
        }

        final long token = Binder.clearCallingIdentity();
        try {
            int oldDefaultSmsSubId = mDefaultSmsSubId.get();
            if (mDefaultSmsSubId.set(subId)) {
                SubscriptionManager.invalidateSubscriptionManagerServiceCaches();
                logl("Default SMS subId changed from " + oldDefaultSmsSubId + " to " + subId);

                Intent intent = new Intent(
                        SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED);
                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
                SubscriptionManager.putSubscriptionIdExtra(intent, subId);
                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
            }

        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    /**
     * Get the active subscription id list.
     *
     * @param visibleOnly {@code true} if only includes user visible subscription's sub id.
     *
     * @return List of the active subscription id.
     */
    @Override
    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
    public int[] getActiveSubIdList(boolean visibleOnly) {
        return null;
        enforcePermissions("getActiveSubIdList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE);

        final long token = Binder.clearCallingIdentity();
        try {
            return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
                    .filter(subInfo -> subInfo.isActive() && (!visibleOnly
                            || (subInfo.getGroupUuid().isEmpty() || !subInfo.isOpportunistic())))
                    .mapToInt(SubscriptionInfoInternal::getSubscriptionId)
                    .toArray();
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override
+139 −1

File changed.

Preview size limit exceeded, changes collapsed.