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

Commit 532e8c20 authored by Roman Birg's avatar Roman Birg Committed by Gerrit Code Review
Browse files

Global actions: 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 a9931cbb
Loading
Loading
Loading
Loading
+66 −18
Original line number Diff line number Diff line
@@ -50,7 +50,6 @@ import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.Manifest;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.os.Build;
@@ -72,6 +71,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;
@@ -97,8 +98,8 @@ import android.widget.TextView;
import cyanogenmod.providers.CMSettings;

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

import static com.android.internal.util.cm.PowerMenuConstants.*;

@@ -137,6 +138,9 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
    // Power menu customizations
    String mActions;

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

    /**
     * @param context everything needs a context :(
     */
@@ -160,9 +164,15 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
        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);
@@ -172,10 +182,59 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
        mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_useFixedVolume);

        updatePowerMenuActions();
    }

    /**
     * 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();

        updatePowerMenuActions();
    }

    /**
@@ -1239,17 +1298,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
                CMSettings.Secure.POWER_MENU_ACTIONS, UserHandle.USER_CURRENT);
    }

    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) {