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

Commit 06f989b7 authored by William Escande's avatar William Escande Committed by Automerger Merge Worker
Browse files

Merge "SatelliteModeListener implementation" am: 03ed0802 am: dd33af37 am: aa283132

parents 80ae126f aa283132
Loading
Loading
Loading
Loading
+132 −0
Original line number Diff line number Diff line
@@ -244,6 +244,8 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {

    private BluetoothNotificationManager mBluetoothNotificationManager;

    private BluetoothSatelliteModeListener mBluetoothSatelliteModeListener;

    // used inside handler thread
    private boolean mQuietEnable = false;
    private boolean mEnable;
@@ -490,6 +492,79 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
        }
    }

    final Runnable mOnSatelliteModeChangedRunnable = () -> {
        onSatelliteModeChanged();
    };

    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
    void onSatelliteModeChanged() {
        int delaySatelliteMs = 0;
        int state = getState();
        Log.d(TAG, "onSatelliteModeChanged state : " + BluetoothAdapter.nameForState(state)
                + ", isSatelliteModeSensitive() : " + isSatelliteModeSensitive()
                + ", isSatelliteModeOn() : " + isSatelliteModeOn());

        if (mHandler.hasCallbacks(mOnSatelliteModeChangedRunnable)) {
            mHandler.removeCallbacks(mOnSatelliteModeChangedRunnable);
        }

        if (state == BluetoothAdapter.STATE_BLE_ON && isBluetoothPersistedStateOn()) {
            delaySatelliteMs = SERVICE_RESTART_TIME_MS;
        }
        if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF
                && state != BluetoothAdapter.STATE_BLE_ON) {
            // If Bluetooth is turning state, should handle event after delay
            delaySatelliteMs = ADD_PROXY_DELAY_MS;
        } else if (mHandler.hasMessages(MESSAGE_ENABLE)
                || mHandler.hasMessages(MESSAGE_DISABLE)
                || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)
                || mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED)
                || mHandler.hasMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE)
                || mHandler.hasMessages(MESSAGE_TIMEOUT_BIND)
                || mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE)) {
            // If Bluetooth restarting, should handle event after delay
            delaySatelliteMs = SERVICE_RESTART_TIME_MS;
        }

        if (delaySatelliteMs > 0) {
            Log.d(TAG, "onSatelliteModeChanged delay MS : " + delaySatelliteMs);
            mHandler.postDelayed(mOnSatelliteModeChangedRunnable, delaySatelliteMs);
        } else {
            handleSatelliteModeChanged();
        }
    }

    private void handleSatelliteModeChanged() {
        if (shouldBluetoothBeOn() && getState() != BluetoothAdapter.STATE_ON) {
            sendEnableMsg(mQuietEnableExternal,
                    BluetoothProtoEnums.ENABLE_DISABLE_REASON_SATELLITE_MODE,
                    mContext.getPackageName());
        } else if (!shouldBluetoothBeOn() && getState() != BluetoothAdapter.STATE_OFF) {
            sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_SATELLITE_MODE,
                    mContext.getPackageName());
        }
    }

    private boolean shouldBluetoothBeOn() {
        if (!isBluetoothPersistedStateOn()) {
            Log.d(TAG, "shouldBluetoothBeOn: User want BT off.");
            return false;
        }

        if (isSatelliteModeOn()) {
            Log.d(TAG, "shouldBluetoothBeOn: BT should be off as satellite mode is on.");
            return false;
        }

        if (isAirplaneModeOn() && isBluetoothPersistedStateOnAirplane()) {
            Log.d(TAG, "shouldBluetoothBeOn: BT should be off as airplaneMode is on.");
            return false;
        }

        Log.d(TAG, "shouldBluetoothBeOn: BT should be on.");
        return true;
    }

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
@@ -684,6 +759,9 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
            Log.w(TAG, "Unable to resolve SystemUI's UID.");
        }
        mSystemUiUid = systemUiUid;

        mBluetoothSatelliteModeListener = new BluetoothSatelliteModeListener(
                this, mBluetoothHandlerThread.getLooper(), context);
    }

    /**
@@ -694,6 +772,33 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
    }

    /**
     * @hide constant copied from {@link Settings.Global}
     * TODO(b/274636414): Migrate to official API in Android V.
     */
    @VisibleForTesting
    static final String SETTINGS_SATELLITE_MODE_RADIOS = "satellite_mode_radios";
    /**
     * @hide constant copied from {@link Settings.Global}
     * TODO(b/274636414): Migrate to official API in Android V.
     */
    @VisibleForTesting
    static final String SETTINGS_SATELLITE_MODE_ENABLED = "satellite_mode_enabled";

    private boolean isSatelliteModeSensitive() {
        final String satelliteRadios = Settings.Global.getString(mContext.getContentResolver(),
                SETTINGS_SATELLITE_MODE_RADIOS);
        return satelliteRadios != null
                && satelliteRadios.contains(Settings.Global.RADIO_BLUETOOTH);
    }

    /** Returns true if satellite mode is turned on. */
    private boolean isSatelliteModeOn() {
        if (!isSatelliteModeSensitive()) return false;
        return Settings.Global.getInt(mContext.getContentResolver(),
                SETTINGS_SATELLITE_MODE_ENABLED, 0) == 1;
    }

    /**
     *  Returns true if airplane mode enhancement feature is enabled
     */
@@ -1238,6 +1343,12 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
                    + " mBinding = " + mBinding + " mState = "
                    + BluetoothAdapter.nameForState(mState));
        }

        if (isSatelliteModeOn()) {
            Log.d(TAG, "enableBle(): not enabling - satellite mode is on.");
            return false;
        }

        updateBleAppCount(token, true, packageName);

        if (mState == BluetoothAdapter.STATE_ON
@@ -1273,6 +1384,11 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
                    + BluetoothAdapter.nameForState(mState));
        }

        if (isSatelliteModeOn()) {
            Log.d(TAG, "disableBle(): not disabling - satellite mode is on.");
            return false;
        }

        if (mState == BluetoothAdapter.STATE_OFF) {
            Log.d(TAG, "disableBLE(): Already disabled");
            return false;
@@ -1399,6 +1515,11 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
            throw new SecurityException("no permission to enable Bluetooth quietly");
        }

        if (isSatelliteModeOn()) {
            Log.d(TAG, "enableNoAutoConnect(): not enabling - satellite mode is on.");
            return false;
        }

        synchronized (mReceiver) {
            mQuietEnableExternal = true;
            mEnableExternal = true;
@@ -1429,6 +1550,11 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
            return false;
        }

        if (isSatelliteModeOn()) {
            Log.d(TAG, "enable(): not enabling - satellite mode is on.");
            return false;
        }

        if (DBG) {
            Log.d(TAG, "enable(" + packageName + "):  mBluetooth=" + mBluetooth + " mBinding="
                    + mBinding + " mState=" + BluetoothAdapter.nameForState(mState));
@@ -1494,6 +1620,11 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
            return false;
        }

        if (isSatelliteModeOn()) {
            Log.d(TAG, "disable: not disabling - satellite mode is on.");
            return false;
        }

        if (DBG) {
            Log.d(TAG, "disable(): mBluetooth=" + mBluetooth + ", persist=" + persist
                    + ", mBinding=" + mBinding);
@@ -3525,3 +3656,4 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
        return BluetoothAdapter.BT_SNOOP_LOG_MODE_DISABLED;
    }
}
+83 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.bluetooth;

import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;

/**
 * The SatelliteModeListener handles system satellite mode change callback and inform
 * BluetoothManagerService on this change.
 */
public class BluetoothSatelliteModeListener {
    private static final String TAG = BluetoothSatelliteModeListener.class.getSimpleName();

    private final BluetoothManagerService mBluetoothManagerService;
    private final BluetoothSatelliteModeHandler mHandler;

    private static final int MSG_SATELLITE_MODE_CHANGED = 0;

    BluetoothSatelliteModeListener(BluetoothManagerService service, Looper looper,
              Context context) {
        Log.d(TAG, " BluetoothSatelliteModeListener");
        mBluetoothManagerService = service;
        mHandler = new BluetoothSatelliteModeHandler(looper);

        context.getContentResolver().registerContentObserver(
                Settings.Global.getUriFor(BluetoothManagerService.SETTINGS_SATELLITE_MODE_RADIOS),
                false, mSatelliteModeObserver);
        context.getContentResolver().registerContentObserver(
                Settings.Global.getUriFor(BluetoothManagerService.SETTINGS_SATELLITE_MODE_ENABLED),
                false, mSatelliteModeObserver);
    }

    private final ContentObserver mSatelliteModeObserver = new ContentObserver(null) {
        @Override
        public void onChange(boolean unused) {
            // Post from system main thread to android_io thread.
            mHandler.sendEmptyMessage(MSG_SATELLITE_MODE_CHANGED);
        }
    };

    private class BluetoothSatelliteModeHandler extends Handler {
        BluetoothSatelliteModeHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            if (msg.what != MSG_SATELLITE_MODE_CHANGED) {
                Log.e(TAG, "Invalid message: " + msg.what);
                return;
            }
            handleSatelliteModeChange();
        }
    }

    @VisibleForTesting
    public void handleSatelliteModeChange() {
        mBluetoothManagerService.onSatelliteModeChanged();
    }
}
+60 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.bluetooth;

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.ContentResolver;
import android.content.Context;
import android.os.Looper;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class BluetoothSatelliteModeListenerTest {

    private BluetoothSatelliteModeListener mBluetoothSatelliteModeListener;

    @Mock private Context mContext;
    @Mock private ContentResolver mContentResolver;
    @Mock private BluetoothManagerService mBluetoothManagerService;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        when(mContext.getContentResolver()).thenReturn(mContentResolver);

        mBluetoothSatelliteModeListener = new BluetoothSatelliteModeListener(
                mBluetoothManagerService, Looper.getMainLooper(), mContext);
    }

    @Test
    public void testHandleSatelliteModeChange_InvokeSatelliteModeChanged() {
        mBluetoothSatelliteModeListener.handleSatelliteModeChange();
        verify(mBluetoothManagerService).onSatelliteModeChanged();
    }
}