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

Commit 25312d31 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Read AirplaneMode only once by event" into main

parents e5e5c339 a837282d
Loading
Loading
Loading
Loading
+38 −35
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
@@ -44,7 +43,7 @@ import com.android.internal.annotations.VisibleForTesting;
 *   <li>Bluetooth LE Audio is connected
 * </ul>
 */
class BluetoothAirplaneModeListener {
class BluetoothAirplaneModeListener extends Handler {
    private static final String TAG = "BluetoothAirplaneModeListener";
    @VisibleForTesting static final String TOAST_COUNT = "bluetooth_airplane_toast_count";

@@ -85,10 +84,11 @@ class BluetoothAirplaneModeListener {
    private long mApmEnabledTime = 0;

    private final BluetoothManagerService mBluetoothManager;
    private final BluetoothAirplaneModeHandler mHandler;
    private final Context mContext;
    private BluetoothModeChangeHelper mAirplaneHelper;
    private BluetoothNotificationManager mNotificationManager;
    private final BluetoothNotificationManager mNotificationManager;

    private boolean mIsAirplaneModeOn;

    @VisibleForTesting int mToastCount = 0;

@@ -97,44 +97,47 @@ class BluetoothAirplaneModeListener {
            Looper looper,
            Context context,
            BluetoothNotificationManager notificationManager) {
        super(looper);

        mBluetoothManager = service;
        mNotificationManager = notificationManager;
        mContext = context;

        mHandler = new BluetoothAirplaneModeHandler(looper);
        mIsAirplaneModeOn = isGlobalAirplaneModeOn(mContext);

        context.getContentResolver()
                .registerContentObserver(
                        Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
                        true,
                        mAirplaneModeObserver);
    }

    private final ContentObserver mAirplaneModeObserver =
            new ContentObserver(null) {
                        new ContentObserver(this) {
                            @Override
                            public void onChange(boolean selfChange) {
                    // Post from system main thread to android_io thread.
                    Message msg = mHandler.obtainMessage(MSG_AIRPLANE_MODE_CHANGED);
                    mHandler.sendMessage(msg);
                                // This is called on the looper and doesn't need a lock
                                boolean isGlobalAirplaneModeOn = isGlobalAirplaneModeOn(mContext);
                                if (mIsAirplaneModeOn == isGlobalAirplaneModeOn) {
                                    Log.d(
                                            TAG,
                                            "Ignore airplane mode change:"
                                                    + (" mIsAirplaneModeOn=" + mIsAirplaneModeOn));
                                    return;
                                }
            };

    private class BluetoothAirplaneModeHandler extends Handler {
        BluetoothAirplaneModeHandler(Looper looper) {
            super(looper);
                                mIsAirplaneModeOn = isGlobalAirplaneModeOn;
                                handleAirplaneModeChange(mIsAirplaneModeOn);
                            }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_AIRPLANE_MODE_CHANGED:
                    handleAirplaneModeChange();
                    break;
                default:
                    Log.e(TAG, "Invalid message: " + msg.what);
                    break;
                        });
    }

    /** Do not use outside of this class to avoid async issues */
    private static boolean isGlobalAirplaneModeOn(Context ctx) {
        return BluetoothServerProxy.getInstance()
                        .settingsGlobalGetInt(
                                ctx.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0)
                == 1;
    }

    /** return true if airplaneMode is currently On */
    boolean isAirplaneModeOn() {
        return mIsAirplaneModeOn;
    }

    /** Call after boot complete */
@@ -157,18 +160,18 @@ class BluetoothAirplaneModeListener {

    @VisibleForTesting
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
    void handleAirplaneModeChange() {
    void handleAirplaneModeChange(boolean isAirplaneModeOn) {
        if (mAirplaneHelper == null) {
            return;
        }
        if (mAirplaneHelper.isAirplaneModeOn()) {
        if (isAirplaneModeOn) {
            mApmEnabledTime = SystemClock.elapsedRealtime();
            mIsBluetoothOnBeforeApmToggle = mAirplaneHelper.isBluetoothOn();
            mIsBluetoothOnAfterApmToggle = shouldSkipAirplaneModeChange();
            mIsMediaProfileConnectedBeforeApmToggle = mAirplaneHelper.isMediaProfileConnected();
            if (mIsBluetoothOnAfterApmToggle) {
                Log.i(TAG, "Ignore airplane mode change");
                // Airplane mode enabled when Bluetooth is being used for audio/headering aid.
                // Airplane mode enabled when Bluetooth is being used for audio/hearing aid.
                // Bluetooth is not disabled in such case, only state is changed to
                // BLUETOOTH_ON_AIRPLANE mode.
                mAirplaneHelper.setSettingsInt(
@@ -218,7 +221,7 @@ class BluetoothAirplaneModeListener {
            mUserToggledBluetoothDuringApm = false;
            mUserToggledBluetoothDuringApmWithinMinute = false;
        }
        mAirplaneHelper.onAirplaneModeChanged(mBluetoothManager);
        mBluetoothManager.onAirplaneModeChanged(isAirplaneModeOn);
    }

    @VisibleForTesting
+12 −13
Original line number Diff line number Diff line
@@ -432,12 +432,12 @@ class BluetoothManagerService {
    private static final Object ON_SWITCH_USER_TOKEN = new Object();

    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
    void onAirplaneModeChanged() {
    void onAirplaneModeChanged(boolean isAirplaneModeOn) {
        mHandler.postDelayed(
                () ->
                        delayModeChangedIfNeeded(
                                ON_AIRPLANE_MODE_CHANGED_TOKEN,
                                () -> handleAirplaneModeChanged(),
                                () -> handleAirplaneModeChanged(isAirplaneModeOn),
                                "onAirplaneModeChanged"),
                ON_AIRPLANE_MODE_CHANGED_TOKEN,
                0);
@@ -468,10 +468,10 @@ class BluetoothManagerService {
    }

    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
    private void handleAirplaneModeChanged() {
    private void handleAirplaneModeChanged(boolean isAirplaneModeOn) {
        synchronized (this) {
            if (isBluetoothPersistedStateOn()) {
                if (isAirplaneModeOn()) {
                if (isAirplaneModeOn) {
                    persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
                } else {
                    persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
@@ -482,12 +482,12 @@ class BluetoothManagerService {

            Log.d(
                    TAG,
                    "Airplane Mode change - current state:  "
                            + BluetoothAdapter.nameForState(st)
                            + ", isAirplaneModeOn()="
                            + isAirplaneModeOn());
                    "handleAirplaneModeChanged(isAirplaneModeOn="
                            + isAirplaneModeOn
                            + ") | current state="
                            + BluetoothAdapter.nameForState(st));

            if (isAirplaneModeOn()) {
            if (isAirplaneModeOn) {
                // Clear registered LE apps to force shut-off
                clearBleApps();

@@ -736,9 +736,8 @@ class BluetoothManagerService {

    /** Returns true if airplane mode is currently on */
    private boolean isAirplaneModeOn() {
        return Settings.Global.getInt(
                        mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0)
                == 1;
        return mBluetoothAirplaneModeListener != null
            && mBluetoothAirplaneModeListener.isAirplaneModeOn();
    }

    /** Returns true if satellite mode is turned on. */
@@ -2644,7 +2643,7 @@ class BluetoothManagerService {
        mHandler.sendEmptyMessageDelayed(MESSAGE_RESTART_BLUETOOTH_SERVICE, ERROR_RESTART_TIME_MS);

        if (repeatAirplaneRunnable) {
            onAirplaneModeChanged();
            onAirplaneModeChanged(isAirplaneModeOn());
        }
    }

+0 −13
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.server.bluetooth;

import static com.android.server.bluetooth.BluetoothAirplaneModeListener.BLUETOOTH_APM_STATE;

import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
@@ -114,18 +113,6 @@ public class BluetoothModeChangeHelper {
        return adapter.isLeEnabled();
    }

    @VisibleForTesting
    public boolean isAirplaneModeOn() {
        return Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
    }

    @VisibleForTesting
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
    public void onAirplaneModeChanged(BluetoothManagerService managerService) {
        managerService.onAirplaneModeChanged();
    }

    @VisibleForTesting
    public int getSettingsInt(String name) {
        return Settings.Global.getInt(mContext.getContentResolver(),
+4 −0
Original line number Diff line number Diff line
@@ -64,6 +64,10 @@ class BluetoothServerProxy {
        return Settings.Secure.getString(contentResolver, name);
    }

    int settingsGlobalGetInt(ContentResolver contentResolver, String name, int def) {
        return Settings.Global.getInt(contentResolver, name, def);
    }

    int getBluetoothPersistedState(ContentResolver resolver, int defaultValue) {
        return Settings.Global.getInt(resolver, Settings.Global.BLUETOOTH_ON, defaultValue);
    }
+26 −15
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ public class BluetoothAirplaneModeListenerTest {
    private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;

    @Mock private Context mContext;
    @Mock private BluetoothServerProxy mBluetoothServerProxy;
    @Mock private ContentResolver mContentResolver;
    @Mock private BluetoothManagerService mBluetoothManagerService;
    @Mock private BluetoothModeChangeHelper mHelper;
@@ -68,7 +69,8 @@ public class BluetoothAirplaneModeListenerTest {
                .thenReturn(BluetoothAirplaneModeListener.MAX_TOAST_COUNT);
        doNothing().when(mHelper).setSettingsInt(anyString(), anyInt());
        doNothing().when(mHelper).showToastMessage();
        doNothing().when(mHelper).onAirplaneModeChanged(any(BluetoothManagerService.class));

        BluetoothServerProxy.setInstanceForTesting(mBluetoothServerProxy);

        mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener(
                mBluetoothManagerService, Looper.getMainLooper(), mContext,
@@ -89,7 +91,6 @@ public class BluetoothAirplaneModeListenerTest {

    @Test
    public void testIgnoreOnAirplanModeChangeApmEnhancement() {
        when(mHelper.isAirplaneModeOn()).thenReturn(true);
        when(mHelper.isBluetoothOn()).thenReturn(true);

        // When APM enhancement is disabled, BT remains on when connected to a media profile
@@ -142,8 +143,8 @@ public class BluetoothAirplaneModeListenerTest {

    @Test
    public void testHandleAirplaneModeChange_InvokeAirplaneModeChanged() {
        mBluetoothAirplaneModeListener.handleAirplaneModeChange();
        verify(mHelper).onAirplaneModeChanged(mBluetoothManagerService);
        mBluetoothAirplaneModeListener.handleAirplaneModeChange(false);
        verify(mBluetoothManagerService).onAirplaneModeChanged(eq(false));
    }

    @Test
@@ -151,13 +152,12 @@ public class BluetoothAirplaneModeListenerTest {
        mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT;
        when(mHelper.isBluetoothOn()).thenReturn(true);
        when(mHelper.isMediaProfileConnected()).thenReturn(true);
        when(mHelper.isAirplaneModeOn()).thenReturn(true);
        mBluetoothAirplaneModeListener.handleAirplaneModeChange();
        mBluetoothAirplaneModeListener.handleAirplaneModeChange(true);

        verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
                BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
        verify(mHelper, times(0)).showToastMessage();
        verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService);
        verify(mBluetoothManagerService, times(0)).onAirplaneModeChanged(anyBoolean());
    }

    @Test
@@ -165,18 +165,16 @@ public class BluetoothAirplaneModeListenerTest {
        mBluetoothAirplaneModeListener.mToastCount = 0;
        when(mHelper.isBluetoothOn()).thenReturn(true);
        when(mHelper.isMediaProfileConnected()).thenReturn(true);
        when(mHelper.isAirplaneModeOn()).thenReturn(true);
        mBluetoothAirplaneModeListener.handleAirplaneModeChange();
        mBluetoothAirplaneModeListener.handleAirplaneModeChange(true);

        verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
                BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
        verify(mHelper).showToastMessage();
        verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService);
        verify(mBluetoothManagerService, times(0)).onAirplaneModeChanged(anyBoolean());
    }

    private void setUpApmNotificationTests() throws Exception {
        when(mHelper.isBluetoothOn()).thenReturn(true);
        when(mHelper.isAirplaneModeOn()).thenReturn(true);
        when(mHelper.isBluetoothOnAPM()).thenReturn(true);
        when(mHelper.getSettingsInt(APM_ENHANCEMENT)).thenReturn(1);
        when(mHelper.getSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, UNUSED)).thenReturn(USED);
@@ -193,7 +191,7 @@ public class BluetoothAirplaneModeListenerTest {
        when(mHelper.getSettingsSecureInt(APM_WIFI_BT_NOTIFICATION, NOTIFICATION_NOT_SHOWN))
                .thenReturn(NOTIFICATION_NOT_SHOWN);

        mBluetoothAirplaneModeListener.handleAirplaneModeChange();
        mBluetoothAirplaneModeListener.handleAirplaneModeChange(true);

        verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
                BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
@@ -209,7 +207,7 @@ public class BluetoothAirplaneModeListenerTest {
        when(mHelper.getSettingsSecureInt(APM_WIFI_BT_NOTIFICATION, NOTIFICATION_NOT_SHOWN))
                .thenReturn(NOTIFICATION_SHOWN);

        mBluetoothAirplaneModeListener.handleAirplaneModeChange();
        mBluetoothAirplaneModeListener.handleAirplaneModeChange(true);

        verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
                BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
@@ -225,7 +223,7 @@ public class BluetoothAirplaneModeListenerTest {
        when(mHelper.getSettingsSecureInt(APM_BT_NOTIFICATION, NOTIFICATION_NOT_SHOWN))
                .thenReturn(NOTIFICATION_NOT_SHOWN);

        mBluetoothAirplaneModeListener.handleAirplaneModeChange();
        mBluetoothAirplaneModeListener.handleAirplaneModeChange(true);

        verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
                BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
@@ -241,7 +239,7 @@ public class BluetoothAirplaneModeListenerTest {
        when(mHelper.getSettingsSecureInt(APM_BT_NOTIFICATION, NOTIFICATION_NOT_SHOWN))
                .thenReturn(NOTIFICATION_SHOWN);

        mBluetoothAirplaneModeListener.handleAirplaneModeChange();
        mBluetoothAirplaneModeListener.handleAirplaneModeChange(true);

        verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
                BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
@@ -262,4 +260,17 @@ public class BluetoothAirplaneModeListenerTest {
        Assert.assertFalse(mBluetoothAirplaneModeListener.shouldPopToast());
        verify(mHelper, times(0)).setSettingsInt(anyString(), anyInt());
    }

    @Test
    public void testFastToggle() {
        boolean expectedIsOn = false;
        // return true on proxy while calling the method with false in order to simulate the
        // settings having already changed after the wake-up of the observer and before calling
        // BluetoothManagerService
        doReturn(1)
                .when(mBluetoothServerProxy)
                .settingsGlobalGetInt(any(), eq(Settings.Global.AIRPLANE_MODE_ON), anyInt());
        mBluetoothAirplaneModeListener.handleAirplaneModeChange(expectedIsOn);
        verify(mBluetoothManagerService).onAirplaneModeChanged(eq(expectedIsOn));
    }
}
Loading