蓝牙开关

本文主要探讨了Android系统设置中的蓝牙开关功能,详细分析了`BluetoothSettings`类的作用,以及`BluetoothEnabler`如何控制蓝牙的开启。在`BluetoothEnabler`的构造方法中,`LocalBluetoothManager`用于封装蓝牙API接口,并通过单例模式管理。`handleStateChanged`方法在界面恢复时获取蓝牙状态,确保界面与实际蓝牙状态同步。此外,蓝牙开启后会显示已配对和可用设备列表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BluetoothSettings

设置 选项中 蓝牙开关的按钮。在settings代码中。
代码路径(packages\apps\Settings\src\com\android\settings\bluetooth\)

BluetoothSettings

//android8.0\packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothSettings.java

public final class BluetoothSettings extends DeviceListPreferenceFragment implements Indexable {
    ...
}

这个类,是蓝牙设置中的主界面。
我们通过这个类来完善对settings中蓝牙相关代码以及类的认识。

蓝牙开关

我们分析一下蓝牙开关按钮都做了什么操作。

//android8.0\packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothSettings.java

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        /* Don't auto start scan if screen reconstructs due to frozen screen*/
        mInitialScanStarted = (savedInstanceState != null);
        mInitiateDiscoverable = true;

        final SettingsActivity activity = (SettingsActivity) getActivity();
        mSwitchBar = activity.getSwitchBar();
        //打开开关
        mBluetoothEnabler = new BluetoothEnabler(activity, new SwitchBarController(mSwitchBar),
            mMetricsFeatureProvider, Utils.getLocalBtManager(activity),
            MetricsEvent.ACTION_BLUETOOTH_TOGGLE);
        mBluetoothEnabler.setupSwitchController();
    }

BluetoothSettings.java是settings中蓝牙相对比较重要的类。在初始化(onActivityCreated)的时候,进行打开开关操作。

调用BluetoothEnabler来开启开关。

BluetoothEnabler构造方法

我们进入BluetoothEnabler的构造方法来看看都做了什么操作。

E:\android8.0\packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothEnabler.java

public BluetoothEnabler(Context context, SwitchWidgetController switchWidget,
            MetricsFeatureProvider metricsFeatureProvider, LocalBluetoothManager manager,
            int metricsEvent, RestrictionUtils restrictionUtils) {
        mContext = context;
        mMetricsFeatureProvider = metricsFeatureProvider;
        //ui选择控件
        mSwitchWidget = switchWidget;
        mSwitch = mSwitchWidget.getSwitch();
        mSwitchWidget.setListener(this);
        mValidListener = false;
        mMetricsEvent = metricsEvent;

        if (manager == null) {
            // 蓝牙不支持。通过判断manager是否为空。
            mLocalAdapter = null;
            mSwitchWidget.setEnabled(false);
        } else {
            //1.1
            //支持蓝牙的时候,是通过manager获取.
            //这个manger是LocalBluetoothManager,这个类是为本地的蓝牙接口适配器,为应用提供接口,同时调用BluetoothAdapter的接口,起到应用和底层的适配作用。
            mLocalAdapter = manager.getBluetoothAdapter();
        }
        mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
        mRestrictionUtils = restrictionUtils;
    }
1.1 LocalBluetoothManager

LocalBluetoothManager类将bluetooth api的接口封装。


public class LocalBluetoothManager {
    private static final String TAG = "LocalBluetoothManager";

    /** Singleton instance. */
    private static LocalBluetoothManager sInstance;

    private final Context mContext;

    /** If a BT-related activity is in the foreground, this will be it. */
    private Context mForegroundActivity;

    private final LocalBluetoothAdapter mLocalAdapter;

    private final CachedBluetoothDeviceManager mCachedDeviceManager;

    /** The Bluetooth profile manager. */
    private final LocalBluetoothProfileManager mProfileManager;

    /** The broadcast receiver event manager. */
    private final BluetoothEventManager mEventManager;

    /**
        获取一个示例
    */
    public static synchronized LocalBluetoothManager getInstance(Context context,
            BluetoothManagerCallback onInitCallback) {
        if (sInstance == null) {
            LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();
            if (adapter == null) {
                return null;
            }
            // This will be around as long as this process is
            Context appContext = context.getApplicationContext();
            sInstance = new LocalBluetoothManager(adapter, appContext);
            if (onInitCallback != null) {
                onInitCallback.onBluetoothManagerInitialized(appContext, sInstance);
            }
        }

        return sInstance;
    }

    //构造方法中new 了几个相关的manager来得到getxxxmanager。
    private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) {
        mContext = context;
        mLocalAdapter = adapter;
        //负责管理蓝牙的缓存(已配对的设备和搜索到的设备)主要都保存在List<CachedBluetoothDevice> mCachedDevices中
        mCachedDeviceManager = new CachedBluetoothDeviceManager(context, this);
        //接收广播,分发底层发出的event。一般android中定义eventxxx类其实就是传递的类。
        mEventManager = new BluetoothEventManager(mLocalAdapter,
                mCachedDeviceManager, context);
        //蓝牙配置协议管理 例如A2dpProfile HeadsetProfile OppProfile PbapClientProfile有个印象即可。后续会进行详细讲解。
        mProfileManager = new LocalBluetoothProfileManager(context,
                mLocalAdapter, mCachedDeviceManager, mEventManager);
    }

   ...

}

这个类的代码很少,用一个单例模式。构造方法中new出3个相应的xxxmanager。并且提供了3个方法来获取xxxmanager。
getCachedDeviceManager,getProfileManager,getEventManager。

获取mLocalAdapter有什么用?

BluetoothEnabler的handleStateChanged方法

我们先看看bluetootheabler的的handleStateChanged方法

// BluetoothEnabler.java
    void handleStateChanged(int state) {
        switch (state) {
            case BluetoothAdapter.STATE_TURNING_ON:
                mSwitchWidget.setEnabled(false);
                break;
            case BluetoothAdapter.STATE_ON:
                setChecked(true);
                mSwitchWidget.setEnabled(true);
                break;
            case BluetoothAdapter.STATE_TURNING_OFF:
                mSwitchWidget.setEnabled(false);
                break;
            case BluetoothAdapter.STATE_OFF:
                setChecked(false);
                mSwitchWidget.setEnabled(true);
                break;
            default:
                setChecked(false);
                mSwitchWidget.setEnabled(true);
        }
    }

这个方法在onresume中被调用

BluetoothEnabler.java

    public void resume(Context context) {
        if (mContext != context) {
            mContext = context;
        }

        maybeEnforceRestrictions();

        if (mLocalAdapter == null) {
            mSwitchWidget.setEnabled(false);
            return;
        }

        // Bluetooth state is not sticky, so set it manually
        handleStateChanged(mLocalAdapter.getBluetoothState());

        mSwitchWidget.startListening();
        mContext.registerReceiver(mReceiver, mIntentFilter);
        mValidListener = true;
    }

我们也就清楚了,进入这个bluetoothEnabler类后。onresume方法来进行获取状态。

传入的参数是

mLocalAdapter.getBluetoothState()

也就是我们之前分析的构造方法中 //1.1

//1.1
mLocalAdapter = manager.getBluetoothAdapter();

的用处。

已配对设备,可用设备

蓝牙打开后,会出现已经配对设备,可用设备。

//android8.0\packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothSettings.java

    @Override
    void addPreferencesForActivity() {
        addPreferencesFromResource(R.xml.bluetooth_settings);
        final Context prefContext = getPrefContext();
        //已经配对设备列表
        mPairedDevicesCategory = new PreferenceCategory(prefContext);
        mPairedDevicesCategory.setKey(KEY_PAIRED_DEVICES);
        mPairedDevicesCategory.setOrder(1);
        //可用设备列表
        getPreferenceScreen().addPreference(mPairedDevicesCategory);

        mAvailableDevicesCategory = new BluetoothProgressCategory(prefContext);
        mAvailableDevicesCategory.setSelectable(false);
        mAvailableDevicesCategory.setOrder(2);
        getPreferenceScreen().addPreference(mAvailableDevicesCategory);

        mMyDevicePreference = mFooterPreferenceMixin.createFooterPreference();
        mMyDevicePreference.setSelectable(false);

        setHasOptionsMenu(true);
    }
我要实现的功能就是能用我手机控制电源的通、对家里的电器的开关进行控制。(目前只是内网操作) 1.首先是蓝牙APP 易安卓编写的,说编写其实我只是修改了其中的一些内容,主要的部分都是通过视频学习的,不过我已经懂得了那些命令,(后面有工程文件,如果不懂,可以去找易锦老师的视频来看,如果找不到,我这存的有),两张界面和代码截图,非常简单,功能也很简单,程序前后修改了两个主要地方,主要原因是测试的时候发现第一种程序会出现错误,在单片机哪里会仔细说明! 操作界面,很简单,打开之后打开蓝牙,然后点击搜索设备,找到你的模块名字,点击之后就可以连接了,连接之后下面会显示蓝牙的名称和地址信息。这个是编程软件中显示的界面,可能和在手机上面运行的不一样,因为有些东西是非可视的,不过不影响,这反而能让我们知道更多的细节。 2.单片机程序 这个程序也很简单,只要学过一些单片机程序的人应该都知道吧,串口通信,设置好通信的波特率,初始化工作做好,然后在串口中断程序里写上你要做的事情就可 以了,这里虽然说11.0592的晶振定时器初值为fd,但是如果用12m的晶振也是可以的,差距不多,没有问题。(说的不怎么专业,我也不是很专业的 人,所以请大神误喷,见笑了!)这里是修改前后的程序不一样的地方,前面的程序是单片机没接收到数据之后读取前一次的IO状态,然后改变其状态,但是测试 的时候发现读取状态有错误,估计是我的电路有问题,第一个继电器可以正常工作,第二个和第三个都有问题,当第一个关闭的时候可以打开,但是当打开的了却不 能关闭,只能用关闭所有的命令来关闭,(找了一下午也没发现问题,元件换了几个都没找到,后来放弃了),后来就换了后面程序,直接发送状态命令,不用判断 当前的状态了,我觉得后面这种可能更好!而且实际测试的时候也可以,没有问题。(补充一下,我发现12M的晶振不能用11.0592M的数据,原因是定时 器计数产生的波特率与9600差距有点大,误差到达了8.5%左右,理论上误差要小于4%才能正常通信,所以通信有错误,虽然能通信,但是数据不对,后来 我把晶振换回来就可以了,看来要实践才知道真理。) 第 一、二张是修改之前的程序,有问题,最后一张是修改之后的,没有问题,后来仔细想了一下,后面一种才是正确的,前面一种的改变状态可能会出现错误,就是手 机上显示的开关是关的,然而实际电路中的电路是开着的(这也是没有数据回传的原因吧,现在只是单向的手机发,模块接的形式,以后再研究)!,但是后面一种 不会出现这个问题! 3.实物电路连接 我也是在测试,所以先用LED 等来代替继电器输出,然后才用到继电器上面。单片机直接放在我做的最小系统版上面,然后用导线来连接到蓝牙开关的小板子上,等测试无误之后再安装在上面,不然不好写程序上去。输出接的是一个小电机,用的一个12v蓄电池代替220V电源,如果要用220V的电源,要注意安全了!提醒一下,绝缘一定要做好,毕竟不是开玩笑的。简单说一下电路连接,首先你得需要焊接一个51单片机最小系统板,(如果这个都不会,那你需要先学习一下,不然肯定是没办法做的)然后是由三极管驱动继电器的电路,记得加二极管,不然三极管很有几率被击穿,最后是蓝牙模块与单片机的连接,电源接好,一般蓝牙模块都是宽电压的,所以直接接到5V电源上,与单片机共用电源,不用什么电压转换,很方便的,把蓝牙模块的TX与单片机的RX连接,就是P3.0那个引脚,RX接单片机的TX,就是P3.1那个引脚,至于继电器哪里你需要接成常开还是常闭的模式就你自己决定了,当然还要加一点录滤波的,因为继电器启动的一瞬间电流很大,担心是单片机死机!这些就是主要的东西了!) 前一张是之前测试用的,后面一张是后来直接把单片机装上去的,看着没有那么乱了,可以看到,当手机上的开关23打开时,电路板上的灯23也是两的,表明继电器已经被打开了。 4.打完收工,作品完成 好了至此最简单的蓝牙开关就做好了,可以躺在床上遥控在远处的风扇了(好吧你们都用的是空调,当我没说!),定时关机(这个功能没做,不过原理都一样,自由发挥了),其他神马的!感兴趣的同学可以试一下,比如说高级一点的外网控制的,把电脑作为服务器,把蓝牙模块接好,和控制器连接起来,然后让手机与电脑通过互联网通信,用手机给电脑发送指令,再通过电脑给蓝牙模块发送指令,比如提前开个空调什么的(提前开风扇没用,还是开你们的空调吧),然后其他什么的东西就自己发挥了!我想这个应该是属于传说中的最简单的物联网吧,虽然没有那么高大上,但是原理是一样的。虽然是手动控制的,不过可以发挥你聪明大脑,让他自动控制啊!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值