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

Commit 03ed0802 authored by William Escande's avatar William Escande Committed by Gerrit Code Review
Browse files

Merge "SatelliteModeListener implementation"

parents 851cda35 947bbee9
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();
    }
}