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

Commit 03e246c0 authored by Cristoforo Cataldo's avatar Cristoforo Cataldo Committed by Bruno Martins
Browse files

GlobalActions: Fix Airplane mode toggle



* This is a squash of

Author: Cristoforo Cataldo <cristoforo.cataldo@gmail.com>
Date:   Fri Jan 31 07:36:29 2014 +0100

    GlobalActions: Set the initial status of airplane mode toggle

    Actually, the initial status of airplane mode toggle is set to false
    when the power menu dialog is initialized.
    This causes an issue if you set airplane mode and then reboot.
    After the reboot, the dialog displays the wrong airplane mode status,
    eg. "Airplane mode is not active", and if you toggle that option, a wrong
    intent is sent again to put ON the airplane mode, instead of OFF, the
    toggle (that is in transition state) will be set disabled.

    This commit fixes this issue.

    Change-Id: Id30355c1e090355645c437086c79ab59093c27a8

Author: Roman Birg <roman@cyngn.com>
Date:   Fri Apr 8 11:37:45 2016 -0700

    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>

Author: Michael W <baddaemon87@gmail.com>
Date:   Thu Apr 23 11:54:30 2020 +0200

    GlobalActions: Prepare for Q

    * The constructor for PhoneStateListener that takes a subId will not
      be supported after P, so adapt by going via subId-specific telephony
      managers
    * Need to store the subId and the listener in order to be able to properly
      unlisten

    Change-Id: I78b842ce17a1ce2c42877b3c32331142e07fefa2

Change-Id: I2199a847d3cf23c8cfff9570fc419b1727fe5e6e
parent 2dc61091
Loading
Loading
Loading
Loading
+78 −24
Original line number Diff line number Diff line
@@ -51,7 +51,6 @@ import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -68,6 +67,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;
@@ -122,7 +123,10 @@ import lineageos.providers.LineageSettings;
import org.lineageos.internal.util.PowerMenuUtils;

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

/**
 * Helper to show the global actions dialog.  Each item is an {@link Action} that
@@ -178,6 +182,10 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
    private String[] mCurrentMenuActions;
    private boolean mIsRestartMenu;

    private BitSet mAirplaneModeBits;
    private final Hashtable<Integer, PhoneStateListener> mPhoneStateListeners =
            new Hashtable<Integer, PhoneStateListener>();

    /**
     * @param context everything needs a context :(
     */
@@ -200,14 +208,16 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
        context.registerReceiver(mBroadcastReceiver, filter);

        ConnectivityManager cm = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);
        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);
@@ -243,6 +253,58 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
        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 = mContext.getSystemService(TelephonyManager.class);
        Set<Integer> keys = mPhoneStateListeners.keySet();
        for (int subId : keys) {
            PhoneStateListener listener = (PhoneStateListener) mPhoneStateListeners.get(subId);
            telephonyManager.createForSubscriptionId(subId).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++) {
                // we need the current index inside the listener, so make it final
                final int subIndex = i;
                int subId = subInfoList.get(subIndex).getSubscriptionId();
                PhoneStateListener subListener = new PhoneStateListener() {
                    @Override
                    public void onServiceStateChanged(ServiceState serviceState) {
                        final boolean inAirplaneMode = serviceState.getState()
                                == ServiceState.STATE_POWER_OFF;
                        mAirplaneModeBits.set(subIndex, 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.put(subId, subListener);
                telephonyManager.createForSubscriptionId(subId).listen(subListener,
                        PhoneStateListener.LISTEN_SERVICE_STATE);
            }
        } else {
            mHasTelephony = false;
        }
        // Set the initial status of airplane mode toggle
        mAirplaneState = getUpdatedAirplaneToggleState();
    }

    /**
     * Show the global actions dialog (creating if necessary)
     *
@@ -1606,17 +1668,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
        }
    };

    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();
        }
    };

    protected void updatePowerMenuActions() {
        ContentResolver resolver = mContext.getContentResolver();
        final String powerMenuActions = LineageSettings.Secure.getStringForUser(resolver,
@@ -1675,15 +1726,18 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
        }
    };

    private ToggleAction.State getUpdatedAirplaneToggleState() {
        return Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.AIRPLANE_MODE_ON, 0) == 1
                    ? ToggleAction.State.On
                    : ToggleAction.State.Off;
    }

    private void onAirplaneModeChanged() {
        // Let the service state callbacks handle the state.
        if (mHasTelephony) return;

        boolean airplaneModeOn = Settings.Global.getInt(
                mContext.getContentResolver(),
                Settings.Global.AIRPLANE_MODE_ON,
                0) == 1;
        mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off;
        mAirplaneState = getUpdatedAirplaneToggleState();
        mAirplaneModeOn.updateState(mAirplaneState);
    }