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

Commit d50458ec authored by Roman Birg's avatar Roman Birg Committed by Sam Mortimer
Browse files

GlobalActions: Fix airplane mode switch for MSIM



MSIM devices are not reporting state changes for SIM slots without SIMs,
so when toggling airplane mode it would get stuck in the intermediate
state because a phone state callback would never happen.

Now we dynamically add phone state listeners for each active SIM slot.
If there is no active SIM slot, we immediately fall back to the
setting-based behavior. When a subscription update occurs (such as
inserting or removing SIM cards, we'll reinitialize the listener and
use the proper mechanism).

Ticket: CYNGNOS-989

Change-Id: Ifa4f418dd11fda6f67ba31f3847bed225187b95c
Signed-off-by: default avatarRoman Birg <roman@cyngn.com>
parent 08cfb882
Loading
Loading
Loading
Loading
+65 −14
Original line number Diff line number Diff line
@@ -63,6 +63,8 @@ import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -87,6 +89,7 @@ import android.widget.TextView;
import com.android.internal.colorextraction.drawable.GradientDrawable;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;

/**
@@ -138,6 +141,9 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn
    private final boolean mShowSilentToggle;
    private final EmergencyAffordanceManager mEmergencyAffordanceManager;

    private BitSet mAirplaneModeBits;
    private final List<PhoneStateListener> mPhoneStateListeners = new ArrayList<>();

    /**
     * @param context everything needs a context :(
     */
@@ -160,9 +166,15 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn
        mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);

        // get notified of phone state changes
        TelephonyManager telephonyManager =
                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
        SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener(
                new SubscriptionManager.OnSubscriptionsChangedListener() {
            @Override
            public void onSubscriptionsChanged() {
                super.onSubscriptionsChanged();
                setupAirplaneModeListeners();
            }
        });
        setupAirplaneModeListeners();
        mContext.getContentResolver().registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
                mAirplaneModeObserver);
@@ -173,6 +185,56 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn
                R.bool.config_useFixedVolume);

        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
    }

    /**
     * Since there are two ways of handling airplane mode (with telephony, we depend on the internal
     * device telephony state), and MSIM devices do not report phone state for missing SIMs, we
     * need to dynamically setup listeners based on subscription changes.
     *
     * So if there is _any_ active SIM in the device, we can depend on the phone state,
     * otherwise fall back to {@link Settings.Global#AIRPLANE_MODE_ON}.
     */
    private void setupAirplaneModeListeners() {
        TelephonyManager telephonyManager =
                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);

        for (PhoneStateListener listener : mPhoneStateListeners) {
            telephonyManager.listen(listener, PhoneStateListener.LISTEN_NONE);
        }
        mPhoneStateListeners.clear();

        final List<SubscriptionInfo> subInfoList = SubscriptionManager.from(mContext)
                .getActiveSubscriptionInfoList();
        if (subInfoList != null) {
            mHasTelephony = true;
            mAirplaneModeBits = new BitSet(subInfoList.size());
            for (int i = 0; i < subInfoList.size(); i++) {
                final int finalI = i;
                PhoneStateListener subListener = new PhoneStateListener(subInfoList.get(finalI)
                        .getSubscriptionId()) {
                    @Override
                    public void onServiceStateChanged(ServiceState serviceState) {
                        final boolean inAirplaneMode = serviceState.getState()
                                == ServiceState.STATE_POWER_OFF;
                        mAirplaneModeBits.set(finalI, inAirplaneMode);

                        // we're in airplane mode if _any_ of the subscriptions say we are
                        mAirplaneState = mAirplaneModeBits.cardinality() > 0
                                ? ToggleAction.State.On : ToggleAction.State.Off;

                        mAirplaneModeOn.updateState(mAirplaneState);
                        if (mAdapter != null) {
                            mAdapter.notifyDataSetChanged();
                        }
                    }
                };
                mPhoneStateListeners.add(subListener);
                telephonyManager.listen(subListener, PhoneStateListener.LISTEN_SERVICE_STATE);
            }
        } else {
            mHasTelephony = false;
        }

        // Set the initial status of airplane mode toggle
        mAirplaneState = getUpdatedAirplaneToggleState();
@@ -1128,17 +1190,6 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn
        }
    };

    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
        @Override
        public void onServiceStateChanged(ServiceState serviceState) {
            if (!mHasTelephony) return;
            final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
            mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off;
            mAirplaneModeOn.updateState(mAirplaneState);
            mAdapter.notifyDataSetChanged();
        }
    };

    private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {