Android -- Airplane Mode对Bluetooth启动的影响

                  Android -- Airplane Mode对Bluetooth启动的影响

 

在Android/IOS系统的手机上,在某些场景下可能会用到Airplane模式;开启这个功能后,它会关闭Wifi/BT功能等无线功能。这里记录下在Android系统上,飞行模式是如何影响开关蓝牙的。

在Android手机等设备上,点击状态栏上的飞行模式按钮时,会作用到SystemUI中的AirplaneModeTitle中:

/** Quick settings tile: Airplane mode **/
public class AirplaneModeTile extends QSTileImpl<BooleanState> {
    private final Icon mIcon =
            ResourceIcon.get(R.drawable.ic_signal_airplane);
    private final GlobalSetting mSetting;

    private boolean mListening;

    public AirplaneModeTile(QSHost host) {
        super(host);

        mSetting = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
            @Override
            protected void handleValueChanged(int value) {
                handleRefreshState(value);
            }
        };
    }

    ......
    @Override
    public void handleClick() {
        boolean airplaneModeEnabled = mState.value;
        MetricsLogger.action(mContext, getMetricsCategory(), !airplaneModeEnabled);
        if (!airplaneModeEnabled && Boolean.parseBoolean(
                SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
            Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
                    new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS), 0);
            return;
        }
        setEnabled(!airplaneModeEnabled);
    }

    private void setEnabled(boolean enabled) {
        final ConnectivityManager mgr =
                (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
        mgr.setAirplaneMode(enabled);
    }
    ........
}

用户点击Airplane Mode按钮时,最终会call到setEnable()中,通过ConnectityManager::setAirplaneMode():

ConnectityManager.java
    /**
     * Set the value for enabling/disabling airplane mode
     *
     * @param enable whether to enable airplane mode or not
     *
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
    public void setAirplaneMode(boolean enable) {
        try {
            mService.setAirplaneMode(enable);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

ConnectivityService.java
    @Override
    public void setAirplaneMode(boolean enable) {
        enforceConnectivityInternalPermission();
        final long ident = Binder.clearCallingIdentity();
        try {
            final ContentResolver cr = mContext.getContentResolver();
            Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, encodeBool(enable));
            Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
            intent.putExtra("state", enable);
            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

可以看到,设置Airplane Mode最终是改变Settings.Global.AIRPLANE_MODE_ON字段,并发送广播向外通知这次改变。在前面分析BT启动的文章中,可以看到BluetoothManagerService有通过注册ContentObserve监听这个字段的变化:

BluetoothManagerService::init()
        String airplaneModeRadios =
                Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS);
        if (airplaneModeRadios == null || airplaneModeRadios.contains(
                Settings.Global.RADIO_BLUETOOTH)) {
            mContentResolver.registerContentObserver(
                    Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
                    mAirplaneModeObserver);//监听Airplane mode改变,相应改变BT状态;这在TV plateform上基本没用
        }
......
private final ContentObserver mAirplaneModeObserver = new ContentObserver(null) {
        @Override
        public void onChange(boolean unused) {
            synchronized (this) {
                if (isBluetoothPersistedStateOn()) {//判断当前BT是否enable
                    if (isAirplaneModeOn()) {//如果当前飞行模式已开启
                        persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);//设置BLUETOOTH_ON字段为BLUETOOTH_ON_AIRPLANE;
                    } else {
                        persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);设置BLUETOOTH_ON字段为BLUETOOTH_ON_BLUETOOTH;
                    }
                }

                int st = BluetoothAdapter.STATE_OFF;
                try {
                    mBluetoothLock.readLock().lock();
                    if (mBluetooth != null) {
                        st = mBluetooth.getState();
                    }
                } catch (RemoteException e) {
                    Slog.e(TAG, "Unable to call getState", e);
                    return;
                } finally {
                    mBluetoothLock.readLock().unlock();
                }

                Slog.d(TAG,
                        "Airplane Mode change - current state:  " + BluetoothAdapter.nameForState(
                                st));

                if (isAirplaneModeOn()) {//Enable飞行模式,需要关闭蓝牙
                    // Clear registered LE apps to force shut-off
                    clearBleApps();

                    // If state is BLE_ON make sure we trigger disableBLE
                    if (st == BluetoothAdapter.STATE_BLE_ON) {//如果之前Bt只是enable ble mode,单独处理
                        try {
                            mBluetoothLock.readLock().lock();
                            if (mBluetooth != null) {
                                addActiveLog(
                                        BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
                                        mContext.getPackageName(), false);
                                mBluetooth.onBrEdrDown();
                                mEnable = false;
                                mEnableExternal = false;
                            }
                        } catch (RemoteException e) {
                            Slog.e(TAG, "Unable to call onBrEdrDown", e);
                        } finally {
                            mBluetoothLock.readLock().unlock();
                        }
                    } else if (st == BluetoothAdapter.STATE_ON) {//如果之前bt的enable mode是normal,普通关闭蓝牙
                        sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
                                mContext.getPackageName());
                    }
                } else if (mEnableExternal) {//关闭飞行模式,如果之前BT是开的,这时要开启蓝牙,恢复之前状态;
                    sendEnableMsg(mQuietEnableExternal,
                            BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
                            mContext.getPackageName());
                }
            }
        }
    };

主要处理是:

  • 开启分析模式时,BLUETOOTH_ON的字段设置为BLUETOOTH_ON_AIRPLANE;否则为BLUETOOTH_ON_BLUETOOTH;这两个值都表示之前蓝牙是enable的,但AIRPLANE会影响蓝牙启动,它拥有更高的优先级来影响enable进程
  • 当前是开启飞行模式,如果此时蓝牙是开的,则需要关掉蓝牙。我们开启蓝牙时,会有两种模式:1)ble only模式,这时无法支持br/edr设备(如音箱),只能支持鼠标、键盘这在低功耗设备;2)普通模式,同时支持ble和br/edr设备
  • 当前是关闭飞行模式,如果之前蓝牙是开的,则需要开启蓝牙

从上一篇分析开机自启蓝牙的流程看到,在handleOnBootPhase()中,只有当BLUETOOTH_ON的值为不为STATE_OFF、且为BLUETOOTH_ON_BLUETOOTH时,才去enable蓝牙;也就是如果这次用户设置了飞行模式、导致蓝牙关闭,下次开机时蓝牙也不会打开。

 

 

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值