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

Commit 4ddebc70 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 8931212 from a36410d1 to tm-qpr1-release

Change-Id: I203fa42eb3a900471d5a01c9ab4ee54a29a8d029
parents 06a69c7a a36410d1
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -248,4 +248,9 @@
    <string name="a2dp_sink_mbs_label">Bluetooth Audio</string>
    <string name="bluetooth_opp_file_limit_exceeded">Files bigger than 4GB cannot be transferred</string>
    <string name="bluetooth_connect_action">Connect to Bluetooth</string>
    <string name="bluetooth_enabled_apm_title">You turned on Bluetooth</string>
    <string name="bluetooth_enabled_apm_message">Your phone will keep Bluetooth on in airplane mode, unless you turn it off while in this mode</string>
    <string name="bluetooth_stays_on_title">Bluetooth stays on</string>
    <string name="bluetooth_and_wifi_stays_on_title">Bluetooth and Wi-Fi stays on</string>
    <string name="bluetooth_and_wifi_stays_on_message">Your phone will keep both on in airplane mode, unless you turn it off while in this mode</string>
</resources>
+114 −7
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.server.bluetooth;

import android.annotation.RequiresPermission;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
@@ -41,18 +43,44 @@ public class BluetoothAirplaneModeListener {
    private static final String TAG = "BluetoothAirplaneModeListener";
    @VisibleForTesting static final String TOAST_COUNT = "bluetooth_airplane_toast_count";

    // keeps track of whether wifi should remain on in airplane mode
    public static final String WIFI_APM_STATE = "wifi_apm_state";
    // keeps track of whether wifi and bt remains on notification was shown
    public static final String APM_WIFI_BT_NOTIFICATION = "apm_wifi_bt_notification";
    // keeps track of whether bt remains on notification was shown
    public static final String APM_BT_NOTIFICATION = "apm_bt_notification";
    // keeps track of whether airplane mode enhancement feature is enabled
    public static final String APM_ENHANCEMENT = "apm_enhancement_enabled";
    // keeps track of whether user changed bt state in airplane mode
    public static final String APM_USER_TOGGLED_BLUETOOTH = "apm_user_toggled_bluetooth";
    // keeps track of whether bt should remain on in airplane mode
    public static final String BLUETOOTH_APM_STATE = "bluetooth_apm_state";
    // keeps track of what the default value for bt should be in airplane mode
    public static final String BT_DEFAULT_APM_STATE = "bt_default_apm_state";
    // keeps track of whether user enabling bt notification was shown
    public static final String APM_BT_ENABLED_NOTIFICATION = "apm_bt_enabled_notification";

    private static final int MSG_AIRPLANE_MODE_CHANGED = 0;
    public static final int NOTIFICATION_NOT_SHOWN = 0;
    public static final int NOTIFICATION_SHOWN = 1;
    public static final int UNUSED = 0;
    public static final int USED = 1;

    @VisibleForTesting static final int MAX_TOAST_COUNT = 10; // 10 times

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

    @VisibleForTesting int mToastCount = 0;

    BluetoothAirplaneModeListener(BluetoothManagerService service, Looper looper, Context context) {
    BluetoothAirplaneModeListener(BluetoothManagerService service, Looper looper, Context context,
            BluetoothNotificationManager notificationManager) {
        mBluetoothManager = service;
        mNotificationManager = notificationManager;
        mContext = context;

        mHandler = new BluetoothAirplaneModeHandler(looper);
        context.getContentResolver().registerContentObserver(
@@ -117,9 +145,29 @@ public class BluetoothAirplaneModeListener {
            // BLUETOOTH_ON_AIRPLANE mode.
            mAirplaneHelper.setSettingsInt(Settings.Global.BLUETOOTH_ON,
                    BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
            if (!isApmEnhancementEnabled() || !isBluetoothToggledOnApm()) {
                if (shouldPopToast()) {
                    mAirplaneHelper.showToastMessage();
                }
            } else {
                if (isWifiEnabledOnApm() && isFirstTimeNotification(APM_WIFI_BT_NOTIFICATION)) {
                    try {
                        sendApmNotification("bluetooth_and_wifi_stays_on_title",
                                "bluetooth_and_wifi_stays_on_message",
                                APM_WIFI_BT_NOTIFICATION);
                    } catch (Exception e) {
                        Log.e(TAG, "APM enhancement BT and Wi-Fi stays on notification not shown");
                    }
                } else if (!isWifiEnabledOnApm() && isFirstTimeNotification(APM_BT_NOTIFICATION)) {
                    try {
                        sendApmNotification("bluetooth_stays_on_title",
                                "bluetooth_enabled_apm_message",
                                APM_BT_NOTIFICATION);
                    } catch (Exception e) {
                        Log.e(TAG, "APM enhancement BT stays on notification not shown");
                    }
                }
            }
            return;
        }
        if (mAirplaneHelper != null) {
@@ -132,10 +180,69 @@ public class BluetoothAirplaneModeListener {
        if (mAirplaneHelper == null) {
            return false;
        }
        if (!mAirplaneHelper.isBluetoothOn() || !mAirplaneHelper.isAirplaneModeOn()
                || !mAirplaneHelper.isMediaProfileConnected()) {
            return false;
        boolean apmEnhancementUsed = isApmEnhancementEnabled() && isBluetoothToggledOnApm();

        // APM feature disabled or user has not used the feature yet by changing BT state in APM
        // BT will only remain on in APM when media profile is connected
        if (!apmEnhancementUsed && mAirplaneHelper.isBluetoothOn()
                && mAirplaneHelper.isAirplaneModeOn()
                && mAirplaneHelper.isMediaProfileConnected()) {
            return true;
        }
        // APM feature enabled and user has used the feature by changing BT state in APM
        // BT will only remain on in APM based on user's last action in APM
        if (apmEnhancementUsed && mAirplaneHelper.isBluetoothOn()
                && mAirplaneHelper.isAirplaneModeOn()
                && mAirplaneHelper.isBluetoothOnAPM()) {
            return true;
        }
        // APM feature enabled and user has not used the feature yet by changing BT state in APM
        // BT will only remain on in APM if the default value is set to on
        if (isApmEnhancementEnabled() && !isBluetoothToggledOnApm()
                && mAirplaneHelper.isBluetoothOn()
                && mAirplaneHelper.isAirplaneModeOn()
                && mAirplaneHelper.isBluetoothOnAPM()) {
            return true;
        }
        return false;
    }

    private boolean isApmEnhancementEnabled() {
        return mAirplaneHelper.getSettingsInt(APM_ENHANCEMENT) == 1;
    }

    private boolean isBluetoothToggledOnApm() {
        return mAirplaneHelper.getSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, UNUSED) == USED;
    }

    private boolean isWifiEnabledOnApm() {
        return mAirplaneHelper.getSettingsInt(Settings.Global.WIFI_ON) != 0
                && mAirplaneHelper.getSettingsSecureInt(WIFI_APM_STATE, 0) == 1;
    }

    private boolean isFirstTimeNotification(String name) {
        return mAirplaneHelper.getSettingsSecureInt(
                name, NOTIFICATION_NOT_SHOWN) == NOTIFICATION_NOT_SHOWN;
    }

    /**
     * Helper method to send APM notification
     */
    public void sendApmNotification(String titleId, String messageId, String notificationState)
            throws PackageManager.NameNotFoundException {
        String btPackageName = mAirplaneHelper.getBluetoothPackageName();
        if (btPackageName == null) {
            Log.e(TAG, "Unable to find Bluetooth package name with "
                    + "APM notification resources");
            return;
        }
        Resources resources = mContext.getPackageManager()
                .getResourcesForApplication(btPackageName);
        int title = resources.getIdentifier(titleId, "string", btPackageName);
        int message = resources.getIdentifier(messageId, "string", btPackageName);
        mNotificationManager.sendApmNotification(
                resources.getString(title), resources.getString(message));
        mAirplaneHelper.setSettingsSecureInt(notificationState,
                NOTIFICATION_SHOWN);
    }
}
+34 −2
Original line number Diff line number Diff line
@@ -16,7 +16,12 @@

package com.android.server.bluetooth;

import static com.android.server.bluetooth.BluetoothAirplaneModeListener.APM_ENHANCEMENT;
import static com.android.server.bluetooth.BluetoothAirplaneModeListener.BT_DEFAULT_APM_STATE;

import android.content.Context;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.Log;

import java.util.ArrayList;
@@ -35,10 +40,22 @@ public class BluetoothDeviceConfigListener {

    private final BluetoothManagerService mService;
    private final boolean mLogDebug;
    private final Context mContext;
    private static final int DEFAULT_APM_ENHANCEMENT = 0;
    private static final int DEFAULT_BT_APM_STATE = 0;

    private boolean mPrevApmEnhancement;
    private boolean mPrevBtApmState;

    BluetoothDeviceConfigListener(BluetoothManagerService service, boolean logDebug) {
    BluetoothDeviceConfigListener(BluetoothManagerService service, boolean logDebug,
            Context context) {
        mService = service;
        mLogDebug = logDebug;
        mContext = context;
        mPrevApmEnhancement = Settings.Global.getInt(mContext.getContentResolver(),
                APM_ENHANCEMENT, DEFAULT_APM_ENHANCEMENT) == 1;
        mPrevBtApmState = Settings.Global.getInt(mContext.getContentResolver(),
                BT_DEFAULT_APM_STATE, DEFAULT_BT_APM_STATE) == 1;
        DeviceConfig.addOnPropertiesChangedListener(
                DeviceConfig.NAMESPACE_BLUETOOTH,
                (Runnable r) -> r.run(),
@@ -59,6 +76,22 @@ public class BluetoothDeviceConfigListener {
                        }
                        Log.d(TAG, "onPropertiesChanged: " + String.join(",", flags));
                    }

                    boolean apmEnhancement = properties.getBoolean(
                            APM_ENHANCEMENT, mPrevApmEnhancement);
                    if (apmEnhancement != mPrevApmEnhancement) {
                        mPrevApmEnhancement = apmEnhancement;
                        Settings.Global.putInt(mContext.getContentResolver(),
                                APM_ENHANCEMENT, apmEnhancement ? 1 : 0);
                    }

                    boolean btApmState = properties.getBoolean(
                            BT_DEFAULT_APM_STATE, mPrevBtApmState);
                    if (btApmState != mPrevBtApmState) {
                        mPrevBtApmState = btApmState;
                        Settings.Global.putInt(mContext.getContentResolver(),
                                BT_DEFAULT_APM_STATE, btApmState ? 1 : 0);
                    }
                    boolean foundInit = false;
                    for (String name : properties.getKeyset()) {
                        if (name.startsWith("INIT_")) {
@@ -72,5 +105,4 @@ public class BluetoothDeviceConfigListener {
                    mService.onInitFlagsChanged();
                }
            };

}
+87 −7
Original line number Diff line number Diff line
@@ -21,6 +21,13 @@ import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGRO
import static android.permission.PermissionManager.PERMISSION_GRANTED;
import static android.permission.PermissionManager.PERMISSION_HARD_DENIED;

import static com.android.server.bluetooth.BluetoothAirplaneModeListener.APM_BT_ENABLED_NOTIFICATION;
import static com.android.server.bluetooth.BluetoothAirplaneModeListener.APM_ENHANCEMENT;
import static com.android.server.bluetooth.BluetoothAirplaneModeListener.APM_USER_TOGGLED_BLUETOOTH;
import static com.android.server.bluetooth.BluetoothAirplaneModeListener.BLUETOOTH_APM_STATE;
import static com.android.server.bluetooth.BluetoothAirplaneModeListener.NOTIFICATION_NOT_SHOWN;
import static com.android.server.bluetooth.BluetoothAirplaneModeListener.USED;

import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
@@ -182,6 +189,9 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
    @VisibleForTesting
    static final int BLUETOOTH_ON_AIRPLANE = 2;

    private static final int BLUETOOTH_OFF_APM = 0;
    private static final int BLUETOOTH_ON_APM = 1;

    private static final int SERVICE_IBLUETOOTH = 1;
    private static final int SERVICE_IBLUETOOTHGATT = 2;

@@ -227,6 +237,8 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {

    private BluetoothDeviceConfigListener mBluetoothDeviceConfigListener;

    private BluetoothNotificationManager mBluetoothNotificationManager;

    // used inside handler thread
    private boolean mQuietEnable = false;
    private boolean mEnable;
@@ -542,6 +554,8 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {

        mUserManager = mContext.getSystemService(UserManager.class);

        mBluetoothNotificationManager = new BluetoothNotificationManager(mContext);

        mIsHearingAidProfileSupported =
                BluetoothProperties.isProfileAshaCentralEnabled().orElse(false);

@@ -602,7 +616,8 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
        if (airplaneModeRadios == null || airplaneModeRadios.contains(
                Settings.Global.RADIO_BLUETOOTH)) {
            mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener(
                    this, mBluetoothHandlerThread.getLooper(), context);
                    this, mBluetoothHandlerThread.getLooper(), context,
                    mBluetoothNotificationManager);
        }

        int systemUiUid = -1;
@@ -627,6 +642,13 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
    }

    /**
     *  Returns true if airplane mode enhancement feature is enabled
     */
    private boolean isApmEnhancementOn() {
        return Settings.Global.getInt(mContext.getContentResolver(), APM_ENHANCEMENT, 0) == 1;
    }

    private boolean supportBluetoothPersistedState() {
        // Set default support to true to copy config default.
        return BluetoothProperties.isSupportPersistedStateEnabled().orElse(true);
@@ -685,6 +707,43 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
        }
    }

    /**
     *  Set the Settings Secure Int value for foreground user
     */
    private void setSettingsSecureInt(String name, int value) {
        if (DBG) {
            Log.d(TAG, "Persisting Settings Secure Int: " + name + "=" + value);
        }

        // waive WRITE_SECURE_SETTINGS permission check
        final long callingIdentity = Binder.clearCallingIdentity();
        try {
            Context userContext = mContext.createContextAsUser(
                    UserHandle.of(ActivityManager.getCurrentUser()), 0);
            Settings.Secure.putInt(userContext.getContentResolver(), name, value);
        } finally {
            Binder.restoreCallingIdentity(callingIdentity);
        }
    }

    /**
     *  Return whether APM notification has been shown
     */
    private boolean isFirstTimeNotification(String name) {
        boolean firstTime = false;
        // waive WRITE_SECURE_SETTINGS permission check
        final long callingIdentity = Binder.clearCallingIdentity();
        try {
            Context userContext = mContext.createContextAsUser(
                    UserHandle.of(ActivityManager.getCurrentUser()), 0);
            firstTime = Settings.Secure.getInt(userContext.getContentResolver(), name,
                    NOTIFICATION_NOT_SHOWN) == NOTIFICATION_NOT_SHOWN;
        } finally {
            Binder.restoreCallingIdentity(callingIdentity);
        }
        return firstTime;
    }

    /**
     * Returns true if the Bluetooth Adapter's name and address is
     * locally cached
@@ -1321,6 +1380,23 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
        synchronized (mReceiver) {
            mQuietEnableExternal = false;
            mEnableExternal = true;
            if (isAirplaneModeOn() && isApmEnhancementOn()) {
                setSettingsSecureInt(BLUETOOTH_APM_STATE, BLUETOOTH_ON_APM);
                setSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, USED);
                if (isFirstTimeNotification(APM_BT_ENABLED_NOTIFICATION)) {
                    final long callingIdentity = Binder.clearCallingIdentity();
                    try {
                        mBluetoothAirplaneModeListener.sendApmNotification(
                                "bluetooth_enabled_apm_title",
                                "bluetooth_enabled_apm_message",
                                APM_BT_ENABLED_NOTIFICATION);
                    } catch (Exception e) {
                        Log.e(TAG, "APM enhancement BT enabled notification not shown");
                    } finally {
                        Binder.restoreCallingIdentity(callingIdentity);
                    }
                }
            }
            // waive WRITE_SECURE_SETTINGS permission check
            sendEnableMsg(false,
                    BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
@@ -1361,12 +1437,15 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
        }

        synchronized (mReceiver) {
            if (!isBluetoothPersistedStateOnAirplane()) {
            if (isAirplaneModeOn() && isApmEnhancementOn()) {
                setSettingsSecureInt(BLUETOOTH_APM_STATE, BLUETOOTH_OFF_APM);
                setSettingsSecureInt(APM_USER_TOGGLED_BLUETOOTH, USED);
            }

            if (persist) {
                persistBluetoothSetting(BLUETOOTH_OFF);
            }
            mEnableExternal = false;
            }
            sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
                    packageName);
        }
@@ -1571,7 +1650,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
            mBluetoothAirplaneModeListener.start(mBluetoothModeChangeHelper);
        }
        registerForProvisioningStateChange();
        mBluetoothDeviceConfigListener = new BluetoothDeviceConfigListener(this, DBG);
        mBluetoothDeviceConfigListener = new BluetoothDeviceConfigListener(this, DBG, mContext);
    }

    /**
@@ -2428,6 +2507,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
                        Log.d(TAG, "MESSAGE_USER_SWITCHED");
                    }
                    mHandler.removeMessages(MESSAGE_USER_SWITCHED);
                    mBluetoothNotificationManager.createNotificationChannels();

                    /* disable and enable BT when detect a user switch */
                    if (mBluetooth != null && isEnabled()) {
+71 −0
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@

package com.android.server.bluetooth;

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

import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHearingAid;
@@ -24,8 +28,12 @@ import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;

import com.android.internal.annotations.VisibleForTesting;
@@ -35,12 +43,16 @@ import com.android.internal.annotations.VisibleForTesting;
 * complex logic.
 */
public class BluetoothModeChangeHelper {
    private static final String TAG = "BluetoothModeChangeHelper";

    private volatile BluetoothA2dp mA2dp;
    private volatile BluetoothHearingAid mHearingAid;
    private volatile BluetoothLeAudio mLeAudio;
    private final BluetoothAdapter mAdapter;
    private final Context mContext;

    private String mBluetoothPackageName;

    BluetoothModeChangeHelper(Context context) {
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mContext = context;
@@ -127,6 +139,24 @@ public class BluetoothModeChangeHelper {
                name, value);
    }

    /**
     * Helper method to get Settings Secure Int value
     */
    public int getSettingsSecureInt(String name, int def) {
        Context userContext = mContext.createContextAsUser(
                UserHandle.of(ActivityManager.getCurrentUser()), 0);
        return Settings.Secure.getInt(userContext.getContentResolver(), name, def);
    }

    /**
     * Helper method to set Settings Secure Int value
     */
    public void setSettingsSecureInt(String name, int value) {
        Context userContext = mContext.createContextAsUser(
                UserHandle.of(ActivityManager.getCurrentUser()), 0);
        Settings.Secure.putInt(userContext.getContentResolver(), name, value);
    }

    @VisibleForTesting
    public void showToastMessage() {
        Resources r = mContext.getResources();
@@ -158,4 +188,45 @@ public class BluetoothModeChangeHelper {
        }
        return leAudio.getConnectedDevices().size() > 0;
    }

    /**
     * Helper method to check whether BT should be enabled on APM
     */
    public boolean isBluetoothOnAPM() {
        Context userContext = mContext.createContextAsUser(
                UserHandle.of(ActivityManager.getCurrentUser()), 0);
        int defaultBtApmState = getSettingsInt(BT_DEFAULT_APM_STATE);
        return Settings.Secure.getInt(userContext.getContentResolver(),
                BLUETOOTH_APM_STATE, defaultBtApmState) == 1;
    }

    /**
     * Helper method to retrieve BT package name with APM resources
     */
    public String getBluetoothPackageName() {
        if (mBluetoothPackageName != null) {
            return mBluetoothPackageName;
        }
        var allPackages = mContext.getPackageManager().getPackagesForUid(Process.BLUETOOTH_UID);
        for (String candidatePackage : allPackages) {
            Resources resources;
            try {
                resources = mContext.getPackageManager()
                        .getResourcesForApplication(candidatePackage);
            } catch (PackageManager.NameNotFoundException e) {
                // ignore, try next package
                Log.e(TAG, "Could not find package " + candidatePackage);
                continue;
            } catch (Exception e) {
                Log.e(TAG, "Error while loading package" + e);
                continue;
            }
            if (resources.getIdentifier("bluetooth_and_wifi_stays_on_title",
                    "string", candidatePackage) == 0) {
                continue;
            }
            mBluetoothPackageName = candidatePackage;
        }
        return mBluetoothPackageName;
    }
}
Loading