Android4.0蓝牙使能的详细解析

毫无疑问,bluetooth的打开是在Settings中进行的操作。因此,冤有头,债有主,我们来到了Settings.java中,果然发现了相关的代码如下:

mBluetoothEnabler =new BluetoothEnabler(context, new Switch(context));

于是,我们得以进入真正的蓝牙操作的殿堂,好好进去看看吧。

复制代码
1、BluetoothEnabler的构造函数public BluetoothEnabler(Context context,Switch switch_) {mContext = context;mSwitch = switch_;//很简单了,去调用一个LocalBluetoothManager类的getInstance,其实会构造该类的
 LocalBluetoothManager manager =LocalBluetoothManager.getInstance(context);if (manager == null) {// Bluetooth is not supported
 mLocalAdapter = null;mSwitch.setEnabled(false);} else {//构造成功后,通过manager得到bluetooth的adapter
 mLocalAdapter =manager.getBluetoothAdapter();}//同时新建一个intent,用于接收ACTION_STATE_CHANGED
 mIntentFilter = newIntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);}2、LocalBluetoothManager类的getInstancepublic static synchronizedLocalBluetoothManager getInstance(Context context) {if (sInstance == null) {//2.1同样的,这个会去调用LocalBluetoothAdapter的getInstance,也会构造该类
 LocalBluetoothAdapter adapter =LocalBluetoothAdapter.getInstance();if (adapter == null) {return null;}// This will be around as long asthis process is
 Context appContext =context.getApplicationContext();//2.2构造LocalBluetoothManager类
 sInstance = newLocalBluetoothManager(adapter, appContext);}return sInstance;}2.1LocalBluetoothAdapter的getInstancestatic synchronized LocalBluetoothAdaptergetInstance() {if (sInstance == null) {//2.1.1通过BluetoothAdapter得到DefaultAdapter
 BluetoothAdapter adapter =BluetoothAdapter.getDefaultAdapter();if (adapter != null) {//2.1.2若有该DefaultAdapter,则构造LocalBluetoothAdapter
 sInstance = newLocalBluetoothAdapter(adapter);}}return sInstance;}2.1.1BluetoothAdapter得到DefaultAdapterpublic static synchronized BluetoothAdaptergetDefaultAdapter() {if (sAdapter == null) {IBinder b =ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);if (b != null) {IBluetooth service =IBluetooth.Stub.asInterface(b);sAdapter = newBluetoothAdapter(service);}}return sAdapter;}2.1.2构造LocalBluetoothAdapter//其实就是 mAdapter的初始化而已
 privateLocalBluetoothAdapter(BluetoothAdapter adapter) {mAdapter = adapter;}2.2构造LocalBluetoothManager类//管理本地蓝牙类,用来在蓝牙API子类上面再封装一个接口
 privateLocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) {mContext = context;//mLocalAdapter初始化为DefaultAdapter中得到的值
 
mLocalAdapter= adapter;//构造CachedBluetoothDeviceManager,用来管理远程蓝牙设备
 mCachedDeviceManager = newCachedBluetoothDeviceManager(context);//2.2.1构建BluetoothEventManager,该类是用来管理广播消息和回调函数的,即分发不同的消息去对UI进行处理
 mEventManager = newBluetoothEventManager(mLocalAdapter,mCachedDeviceManager, context);//2.2.2该类提供对不同LocalBluetoothProfile object的访问
 mProfileManager = newLocalBluetoothProfileManager(context,mLocalAdapter,mCachedDeviceManager, mEventManager);}2.2.1构建BluetoothEventManagerBluetoothEventManager(LocalBluetoothAdapteradapter,CachedBluetoothDeviceManagerdeviceManager, Context context) {mLocalAdapter = adapter;mDeviceManager = deviceManager;//创建两个IntentFilter
 mAdapterIntentFilter = newIntentFilter();//这里没有对mProfileIntentFilter进行初始化,这个在LocalBluetoothProfileManager的addProfile中实现
 mProfileIntentFilter = newIntentFilter();//创建一个Handler的Hash表
 mHandlerMap = new HashMap<String,Handler>();mContext = context;//注册对adapter和Device的几个广播消息的处理回调函数//add action到mAdapterIntentFilter// Bluetooth on/off broadcasts
 addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, newAdapterStateChangedHandler());// Discovery broadcasts
 addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, newScanningStateChangedHandler(true));addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, newScanningStateChangedHandler(false));addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());addHandler(BluetoothDevice.ACTION_DISAPPEARED, newDeviceDisappearedHandler());addHandler(BluetoothDevice.ACTION_NAME_CHANGED, newNameChangedHandler());// Pairing broadcasts
 addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, newBondStateChangedHandler());addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, newPairingCancelHandler());// Fine-grained state broadcasts
 addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, newClassChangedHandler());addHandler(BluetoothDevice.ACTION_UUID,new UuidChangedHandler());// Dock event broadcasts
 addHandler(Intent.ACTION_DOCK_EVENT,new DockEventHandler());//mAdapterIntentFilter的接收处理函数
 mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);}2.2.2构造LocalBluetoothProfileManager类LocalBluetoothProfileManager(Contextcontext,LocalBluetoothAdapter adapter,CachedBluetoothDeviceManagerdeviceManager,BluetoothEventManager eventManager){mContext = context;//各个类之间进行关联
 mLocalAdapter = adapter;mDeviceManager = deviceManager;mEventManager = eventManager;// pass this reference to adapter andevent manager (circular dependency)
 mLocalAdapter.setProfileManager(this);mEventManager.setProfileManager(this);ParcelUuid[] uuids =adapter.getUuids();// uuids may be null if Bluetooth isturned offif (uuids != null) {//假如已经有了uuid,根据uuid来add并new对应的profile,只针对A2DP,HFP,HSP,OPP四个profile,HID和PAN在下面,每次都add
 updateLocalProfiles(uuids);}// Always add HID and PAN profiles//加入HID和PAN两个profile
 mHidProfile = new HidProfile(context,mLocalAdapter);addProfile(mHidProfile,HidProfile.NAME,BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);mPanProfile = new PanProfile(context);addPanProfile(mPanProfile,PanProfile.NAME,BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);Log.d(TAG,"LocalBluetoothProfileManager construction complete");}好吧,其实我们被骗了,刚刚只是一个路引,不是真正的操作,真正的操作向来都是从你滑动界面那个on/off键开始的,因此我们决定把这个键的处理给揪出来。在Settings界面上一共就只有两个on/off键,一个是wifi,另一个就是蓝牙了,我们从这个代码入手:case HEADER_TYPE_SWITCH://其实写这个代码的人也比较心虚,假如switch多一点,下面就要重写了// Would need a differenttreatment if the main menu had more switchesif (header.id ==R.id.wifi_settings) {mWifiEnabler.setSwitch(holder.switch_);} else {//这个就是处理了,上面的路引没有白做啊
 mBluetoothEnabler.setSwitch(holder.switch_);}3、mBluetoothEnabler.setSwitch分析public void setSwitch(Switch switch_) {//若是和上次相同,则不做任何事情,可以理解,代码也懒嘛if (mSwitch == switch_) return;//把上次的switch的changelistener清空
 mSwitch.setOnCheckedChangeListener(null);mSwitch = switch_;//重设这次的switch的changelistener
 mSwitch.setOnCheckedChangeListener(this);int bluetoothState =BluetoothAdapter.STATE_OFF;//获取getBluetoothState,这个过程也会同步一下state,防止改变if (mLocalAdapter != null)bluetoothState = mLocalAdapter.getBluetoothState();//根据状态设置一下两个标志位boolean isOn = bluetoothState ==BluetoothAdapter.STATE_ON;boolean isOff = bluetoothState ==BluetoothAdapter.STATE_OFF;//设置checked的状态位。注意,假如这里状态发生了改变,则会调用this.onCheckedChanged来进行处理
 mSwitch.setChecked(isOn);if(WirelessSettings.isRadioAllowed(mContext, Settings.System.RADIO_BLUETOOTH)) {//有bluetooth或者不是airplane,则该switch不变灰,否则,灰的。
 mSwitch.setEnabled(isOn || isOff);} else {mSwitch.setEnabled(false);}}4、onCheckedChanged在switch状态发生改变后,会调用这个地方的回调函数进行处理。public void onCheckedChanged(CompoundButtonbuttonView, boolean isChecked) {// Show toast message if Bluetooth isnot allowed in airplane mode//若是打开的话,就需要检查一下是否allow Bluetooth(radio,airplane的check)if (isChecked &&!WirelessSettings.isRadioAllowed(mContext,Settings.System.RADIO_BLUETOOTH)) {Toast.makeText(mContext,R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();// Reset switch to off//若是不对的话,reset为off
 buttonView.setChecked(false);}if (mLocalAdapter != null) {//4.1设置scanmode,放心,它会判断state的,不是STATE_ON,会直接返回false的
 mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);//4.2使能或不使能Bluetooth了
 mLocalAdapter.setBluetoothEnabled(isChecked);}//过程中还是会反灰,直到setBluetoothEnabled的结果返回会改变switch的状态
 mSwitch.setEnabled(false);}4.1设置scanmod会调用adapter中的setScanMode,直接去看就可以了,事实上就是设置了两个property标志,没什么public boolean setScanMode(int mode) {//这里把这个代码写出来就是证明一下,STATE_ON才会真正做下去,否则免谈if (getState() != STATE_ON) returnfalse;//这里会调用对应server中的setScanModereturn setScanMode(mode, 120);}public synchronized boolean setScanMode(intmode, int duration) {//这里有个permission,好像和2.3中不一样,注意一下     mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,"NeedWRITE_SECURE_SETTINGS permission");boolean pairable;boolean discoverable;switch (mode) {case BluetoothAdapter.SCAN_MODE_NONE:pairable = false;discoverable = false;break;caseBluetoothAdapter.SCAN_MODE_CONNECTABLE://开始就是这里了,可pairable,但是不可discoverable
 pairable = true;discoverable = false;break;caseBluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:pairable = true;discoverable = true;if (DBG) Log.d(TAG, "BTDiscoverable for " + duration + " seconds");break;default:Log.w(TAG, "Requested invalidscan mode " + mode);return false;}//设置这两个property标志
 setPropertyBoolean("Discoverable", discoverable);setPropertyBoolean("Pairable", pairable);return true;}4.2setBluetoothEnabled分析public void setBluetoothEnabled(booleanenabled) {//根据enabled的标志设置是enable还是disable,在2.3中,这个地方就是bt_enable哦,这里还不知道,我们在第5步进行详细的分析boolean success = enabled? mAdapter.enable(): mAdapter.disable();//成功了,设置对应的状态位if (success) {setBluetoothStateInt(enabled?BluetoothAdapter.STATE_TURNING_ON:BluetoothAdapter.STATE_TURNING_OFF);} else {if (Utils.V) {Log.v(TAG,"setBluetoothEnabled call, manager didn't return " +"success forenabled: " + enabled);}//同步一下设置的状态
 syncBluetoothState();}}}5、mAdapter.enable或者mAdapter.disable就先分析enable吧,它会调用对应server端的enable(ture),我们来看看源码public synchronized boolean enable(booleansaveSetting) {mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,"Need BLUETOOTH_ADMIN permission");// Airplane mode can prevent Bluetoothradio from being turned on.//检查是否是飞行模式if (mIsAirplaneSensitive &&isAirplaneModeOn() && !mIsAirplaneToggleable) {return false;}//5.1注意与2.3的不同,在2.3中,这里会调用enablethread去调用native的bt_enable,而4.0没有这么做。没事,我们来分析4.0怎么做的。
 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON,saveSetting);return true;}5.1mBluetoothState.sendMessage简单理解一下,mBluetoothState是BluetoothAdapterStateMachine类。因此,在分析的之前,简单说一下,它其实就是类似一个状态转换图,根据你所处于的状态,然后再判断收到的操作,进行不同的处理。根据构造函数中的setInitialState(mPowerOff);可以知道初始状态是PowerOff。但是从它给出的状态机可以看出,在PowerOff的状态时,它是通过TURN_HOT/TURN_ON来改变到HotOff状态的,然后才会收到USER_TURN_ON,去该变到BluetootOn的状态。因此,可以肯定的是我们这里的USER_TURN_ON不是它收到的第一个message,因此我们去纠结一下它是从哪里开始改变PowerOff的状态:extra1,然后再来看这里的处理吧:5.2。extra1、mAdapter.enable之前的状态机转变众所周知,android在启动之后会启动一个serverThread的线程,通过这个线程会启动一系列的服务。我们的蓝牙服务也是在这里启动的,android4.0其实在这个地方对状态机进行了修改,我们来看一下源码:该代码位于framworks/base/services/java/com/android/server/systemserver.javaBluetoothServicebluetooth = null;BluetoothA2dpServicebluetoothA2dp = null;//模拟器上是不支持Bluetooth的,工厂测试模式也没有Bluetooth(这个不了解)// Skip Bluetooth if we have anemulator kernel// TODO: Use a more reliable checkto see if this product should// support Bluetooth - see bug988521if(SystemProperties.get("ro.kernel.qemu").equals("1")) {Slog.i(TAG, "No BluetoohService (emulator)");} else if (factoryTest ==SystemServer.FACTORY_TEST_LOW_LEVEL) {Slog.i(TAG, "No BluetoothService (factory test)");} else {Slog.i(TAG, "BluetoothService");//新建Bluetoothservice,并把他加入到ServiceManager中
 bluetooth = newBluetoothService(context);ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE,bluetooth);//extra1.1在启动Bluetooth服务后进行一些初始化,呵呵,这里就对状态机进行了改变
 bluetooth.initAfterRegistration();//新建了BluetoothA2dpService,并把之加入到了ServiceManager中
 
bluetoothA2dp= new BluetoothA2dpService(context, bluetooth);ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,bluetoothA2dp);//extra1.2同样的要在之后做些init的工作
 bluetooth.initAfterA2dpRegistration();//得到是否飞行int airplaneModeOn =Settings.System.getInt(mContentResolver,Settings.System.AIRPLANE_MODE_ON, 0);//看Bluetooth是否on,若是打开的状态(没有飞行),则这里会调用enable去打开int bluetoothOn =Settings.Secure.getInt(mContentResolver,Settings.Secure.BLUETOOTH_ON, 0);if (airplaneModeOn == 0&& bluetoothOn != 0) {bluetooth.enable();}}extra1.1initAfterRegistration分析public synchronized voidinitAfterRegistration() {//得到default的adapter
 mAdapter =BluetoothAdapter.getDefaultAdapter();//创建BluetoothAdapterStateMachine,初始化几个状态,并设初始状态位POWEROFF,这里同时新建了一个EventLoop
 mBluetoothState = newBluetoothAdapterStateMachine(mContext, this, mAdapter);mBluetoothState.start();//根据这个xml的bool变量来决定是否先期TURN_HOT,该变量位于frameworks/base/core/res/res/values/config.xml中,默认为trueif (mContext.getResources().getBoolean(com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {//extra1.2发送TURN_HOT的状态变化message
 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.TURN_HOT);}//得到对应的EventLoop
 mEventLoop =mBluetoothState.getBluetoothEventLoop();}extra1.2  TURN_HOT message的处理/*** Bluetooth module's power is off,firmware is not loaded.*/private class PowerOff extends State {@Overridepublic void enter() {if (DBG) log("Enter PowerOff:" + getCurrentMessage().what);}@Overridepublic boolean processMessage(Messagemessage) {log("PowerOff process message:" + message.what);boolean retValue = HANDLED;switch(message.what) {……case TURN_HOT://extra1.3这里就是我们寻找了千年的bt_enable所在的地方。我们去看看if (prepareBluetooth()) {//extra1.5转变状态到warmup,在prepareBluetooth真正完成后,这个状态还会发生改变
 transitionTo(mWarmUp);}break;……extra1.3prepareBluetooth分析看英文注释就知道了,不解释/*** Turn on Bluetooth Module, Loadfirmware, and do all the preparation* needed to get the Bluetooth Moduleready but keep it not discoverable* and not connectable.* The last step of this method sets upthe local service record DB.* There will be a event reporting thestatus of the SDP setup.*/private boolean prepareBluetooth() {//extra1.4首先还是调用了enableNative的本地方法,到这里你会发现终于和2.3相似了(不过请注意调用的时机不同了,这个在初始化,而2.3在界面的on/off滑动的时候),它还是会调用bt_enable,这个就会调用对应的set_bluetooth_power了if(mBluetoothService.enableNative() != 0) {return false;}// try to start event loop, give 2attempts//尝试两次去start event loopint retryCount = 2;boolean eventLoopStarted = false;while ((retryCount-- > 0)&& !eventLoopStarted) {mEventLoop.start();// it may take a moment for theother thread to do its// thing.  Check periodically for a while.int pollCount = 5;while ((pollCount-- > 0)&& !eventLoopStarted) {if(mEventLoop.isEventLoopRunning()) {eventLoopStarted =true;break;}try {Thread.sleep(100);} catch(InterruptedException e) {log("prepareBluetooth sleep interrupted: " + pollCount);break;}}}//出错处理if (!eventLoopStarted) {mBluetoothService.disableNative();return false;}// get BluetoothService ready//建立native data以及SDP相关的一些操作,这里将会产生PropertyChanged的UUIDs的signal,对该信号的处理会对状态发生改变,详细分析见extra1.5if(!mBluetoothService.prepareBluetooth()) {mEventLoop.stop();mBluetoothService.disableNative();return false;}//设置一个prepare的超时处理,在该时间内没有收到UUID changed的signal将会进行错误处理
 sendMessageDelayed(PREPARE_BLUETOOTH_TIMEOUT,PREPARE_BLUETOOTH_TIMEOUT_TIME);return true;}}extra1.4bt_enable分析intbt_enable() {LOGV(__FUNCTION__);int ret = -1;int hci_sock = -1;int attempt;//power的设置,on。不解释,可加入对应板子的gpio口的处理,默认就只用了rfkill的处理if (set_bluetooth_power(1) < 0) gotoout;//开始hciattach服务,这个我们也做了修改,加入了rtk_h5
 LOGI("Starting hciattachdaemon");if (property_set("ctl.start","hciattach") < 0) {LOGE("Failed to starthciattach");set_bluetooth_power(0);goto out;}// Try for 10 seconds, this can onlysucceed once hciattach has sent the// firmware and then turned on hci devicevia HCIUARTSETPROTO ioctlfor (attempt = 1000; attempt > 0;  attempt--) {//创建hci_sock
 hci_sock = create_hci_sock();if (hci_sock < 0) goto out;//调用ioctl的HCIDEVUP,来判断hciattach是否已经ok了。
 ret = ioctl(hci_sock, HCIDEVUP,HCI_DEV_ID);LOGI("bt_enable: ret: %d, errno:%d", ret, errno);if (!ret) {break;} else if (errno == EALREADY) {LOGW("Bluetoothd alreadystarted, unexpectedly!");break;}close(hci_sock);//等待10 ms后再试一次
 usleep(100000);  // 100 ms retry delay
 }//10s都没有搞定,需要做个失败的处理if (attempt == 0) {LOGE("%s: Timeout waiting for HCIdevice to come up, error- %d, ",__FUNCTION__, ret);if (property_set("ctl.stop","hciattach") < 0) {LOGE("Error stoppinghciattach");}set_bluetooth_power(0);goto out;}//启动bluetoothd服务
 LOGI("Starting bluetoothddeamon");if (property_set("ctl.start","bluetoothd") < 0) {LOGE("Failed to startbluetoothd");set_bluetooth_power(0);goto out;}ret = 0;out://关闭hci_sockif (hci_sock >= 0) close(hci_sock);return ret;}extra 1.5 PropetyChanged的UUIDs的处理event_filter是用来对bluez的dbus的signal进行监听的,有signal产生后,会在这里进行处理。因此,我们直接到这里看看该怎么处理。//Called by dbus during WaitForAndDispatchEventNative()
 
staticDBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,void*data) {native_data_t *nat;JNIEnv *env;DBusError err;DBusHandlerResult ret;//err的一个初始化
 dbus_error_init(&err);//得到参数
 nat = (native_data_t *)data;nat->vm->GetEnv((void**)&env,nat->envVer);if (dbus_message_get_type(msg) !=DBUS_MESSAGE_TYPE_SIGNAL) {LOGV("%s: not interested (not asignal).", __FUNCTION__);returnDBUS_HANDLER_RESULT_NOT_YET_HANDLED;}LOGV("%s: Received signal %s:%s from%s", __FUNCTION__,dbus_message_get_interface(msg),dbus_message_get_member(msg),dbus_message_get_path(msg));env->PushLocalFrame(EVENT_LOOP_REFS);……//PropertyChanged这个signal的处理
 } else if (dbus_message_is_signal(msg,"org.bluez.Adapter","PropertyChanged")) {//由msg解析参数
 jobjectArray str_array =parse_adapter_property_change(env, msg);if (str_array != NULL) {/* Check if bluetoothd has(re)started, if so update the path. */jstring property =(jstring)env->GetObjectArrayElement(str_array, 0);const char *c_property =env->GetStringUTFChars(property, NULL);//检查Property是否startedif (!strncmp(c_property,"Powered", strlen("Powered"))) {//若是powered,则看value是否是true,是ture就得到对应的path
 jstring value =(jstring)env->GetObjectArrayElement(str_array, 1);const char *c_value =env->GetStringUTFChars(value, NULL);if (!strncmp(c_value,"true", strlen("true")))nat->adapter =get_adapter_path(nat->conn);env->ReleaseStringUTFChars(value, c_value);}env->ReleaseStringUTFChars(property, c_property);//extra1.6调用对应的method_onPropertyChanged函数,该method对应的onPropertyChanged函数
 env->CallVoidMethod(nat->me,method_onPropertyChanged,str_array);} elseLOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);goto success;……extra1.6真正的处理函数onPropertyChanged分析/*** Called by native code on aPropertyChanged signal from* org.bluez.Adapter. This method is alsocalled from* {@link BluetoothAdapterStateMachine} toset the "Pairable"* property when Bluetooth is enabled.** @param propValues a string arraycontaining the key and one or more* values.*//*package*/ void onPropertyChanged(String[]propValues) {BluetoothAdapterPropertiesadapterProperties =mBluetoothService.getAdapterProperties();//先fill up cacheif (adapterProperties.isEmpty()) {// We have got a property changebefore// we filled up our cache.
 adapterProperties.getAllProperties();}log("Property Changed: " +propValues[0] + " : " + propValues[1]);String name = propValues[0];……//对UUIDs的处理
 } else if(name.equals("Devices") || name.equals("UUIDs")) {String value = null;int len =Integer.valueOf(propValues[1]);if (len > 0) {StringBuilder str = newStringBuilder();for (int i = 2; i <propValues.length; i++) {str.append(propValues[i]);str.append(",");}value = str.toString();}//把name和value值加入到property的map中
 adapterProperties.setProperty(name,value);//extra1.7有UUIDs的change signal会刷新Bluetooth的Stateif (name.equals("UUIDs")){mBluetoothService.updateBluetoothState(value);}//对Pairable和Discoverable的处理
 } else if(name.equals("Pairable") || name.equals("Discoverable")) {adapterProperties.setProperty(name,propValues[1]);if(name.equals("Discoverable")) {//5.6发送SCAN_MODE_CHANGED的msg,去改变状态机      mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SCAN_MODE_CHANGED);
 }//设置对应的property
 String pairable =name.equals("Pairable") ? propValues[1] :adapterProperties.getProperty("Pairable");String discoverable =name.equals("Discoverable") ? propValues[1] :adapterProperties.getProperty("Discoverable");// This shouldn't happen, unlessAdapter Properties are null.if (pairable == null ||discoverable == null)return;int mode =BluetoothService.bluezStringToScanMode(pairable.equals("true"),discoverable.equals("true"));if (mode >= 0) {//当pairable和discoverable均为true的时候,会发送一个ACTION_SCAN_MODE_CHANGED的广播消息
 Intent intent = newIntent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mode);intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);mContext.sendBroadcast(intent,BLUETOOTH_PERM);}}……extra1.7  UUIDs改变带来的State的刷新/*** This function is called from BluetoothEvent Loop when onPropertyChanged* for adapter comes in with UUID property.* @param uuidsThe uuids of adapter asreported by Bluez.*//*package*/ synchronized voidupdateBluetoothState(String uuids) {ParcelUuid[] adapterUuids =convertStringToParcelUuid(uuids);//为什么必须包含所有已经有的uuid??感觉有点反了,再看看if (mAdapterUuids != null &&BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {//放SERVICE_RECORD_LOADED的信息,此时,处于warm up状态,看extra1.8分析状态如何继续改变          mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SERVICE_RECORD_LOADED);
 }}extra1.8 UUIDs对状态机改变/*** Turning on Bluetooth module's power,loading firmware, starting* event loop thread to listen on Bluetoothmodule event changes.*/private class WarmUp extends State {@Overridepublic void enter() {if (DBG) log("Enter WarmUp:" + getCurrentMessage().what);}@Overridepublic boolean processMessage(Messagemessage) {log("WarmUp process message:" + message.what);boolean retValue = HANDLED;switch(message.what) {case SERVICE_RECORD_LOADED://可以看到,首先会把当时从poweroff过来的一个超时message拿remove了。
 removeMessages(PREPARE_BLUETOOTH_TIMEOUT);//转到hotoff状态,在hotoff状态仍会接收到多个SERVICE_RECORD_LOADED的msg,但是那个状态下该msg将没有任何handled,因此会一直处于hotoff状态
 transitionTo(mHotOff);break;……5.2mAdapter.enable中mBluetoothState.sendMessage后的状态机处理由extra的分析可知,此时,Bluetooth的State已经处于HotOff状态了,所以,从这里开始处理State的变换。/*** Bluetooth Module has powered, firmwareloaded, event loop started,* SDP loaded, but the modules staysnon-discoverable and* non-connectable.*/private class HotOff extends State {@Overridepublic void enter() {if (DBG) log("Enter HotOff:" + getCurrentMessage().what);}@Overridepublic boolean processMessage(Messagemessage) {log("HotOff process message:" + message.what);boolean retValue = HANDLED;switch(message.what) {case USER_TURN_ON://发出BluetoothAdapter.STATE_TURNING_ON的广播消息
 broadcastState(BluetoothAdapter.STATE_TURNING_ON);if ((Boolean) message.obj){//就是把Settings.Secure.BLUETOOTH_ON设为1。用于标志Bluetooth enable了
 persistSwitchSetting(true);}// let it fall toTURN_ON_CONTINUE://$FALL-THROUGH$//注意上面没有break哦case TURN_ON_CONTINUE://这里就是把Bluetooth设为connectable就是Powered=1,这里就把prepareBluetooth中设置的不可连接重新设置回来了。这个重连会产生一些新的变化,它会发送WRITE_SCAN_ENABLE的cmd,因此在该cmd_complete时会有一些新的处理:5.3,它会再次引起状态机的改变:5.6
 mBluetoothService.switchConnectable(true);//进入到Switching状态
 transitionTo(mSwitching);break;……5.3 WRITE_SCAN_ENABLE在cmd_complete后的处理在bluez中是用cmd_complete函数来监视发出cmd完成后的处理的。该函数具体如下:staticinline void cmd_complete(int index, void *ptr){structdev_info *dev = &devs[index];evt_cmd_complete*evt = ptr;uint16_topcode = btohs(evt->opcode);uint8_tstatus = *((uint8_t *) ptr + EVT_CMD_COMPLETE_SIZE);switch(opcode) {……//WRITE_SCAN_ENABLE命令完成的处理函数,会再发一个READ_SCAN_ENABLE的命令
 
casecmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):hci_send_cmd(dev->sk,OGF_HOST_CTL, OCF_READ_SCAN_ENABLE,0,NULL);break;//5.4紧接着就是对READ_SCAN_ENABLE命令完成的处理,它是通过read_scan_complete来实现的
 
casecmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE):ptr+= sizeof(evt_cmd_complete);read_scan_complete(index,status, ptr);break;……}5.4 read_scan命令完成的处理staticvoid read_scan_complete(int index, uint8_t status, void *ptr){structbtd_adapter *adapter;read_scan_enable_rp*rp = ptr;DBG("hci%dstatus %u", index, status);//由index得到对应的adapter
 
adapter= manager_find_adapter_by_id(index);if(!adapter) {error("Unableto find matching adapter");return;}//5.5这里算是一个通知adapter,mode改变了。
 
adapter_mode_changed(adapter,rp->enable);}5.5通知adapter,mode发生了改变voidadapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode){constgchar *path = adapter_get_path(adapter);gbooleandiscoverable, pairable;DBG("old0x%02x new 0x%02x", adapter->scan_mode, scan_mode);//若相同,则nothing todoif(adapter->scan_mode == scan_mode){#ifdefBOARD_HAVE_BLUETOOTH_BCM/*we may reset scan_mode already inbtd_adapter_stop(), so comes to here*/set_mode_complete(adapter);#endifreturn;}//把discoverable的timeout清空
 
adapter_remove_discov_timeout(adapter);//这里开始,是设为SCAN_PAGE| SCAN_INQUIRYswitch(scan_mode) {caseSCAN_DISABLED:adapter->mode= MODE_OFF;discoverable= FALSE;pairable= FALSE;break;caseSCAN_PAGE:adapter->mode= MODE_CONNECTABLE;discoverable= FALSE;pairable= adapter->pairable;break;case(SCAN_PAGE | SCAN_INQUIRY)://设一下模式,在有reply要求的情况下,该步骤还是很重要的
 
adapter->mode= MODE_DISCOVERABLE;discoverable= TRUE;pairable= adapter->pairable;//还要设一个discoverable的时间if(adapter->discov_timeout != 0)adapter_set_discov_timeout(adapter,adapter->discov_timeout);break;caseSCAN_INQUIRY:/*Address the scenario where a low-level application like* hciconfig changed the scan mode */if(adapter->discov_timeout != 0)adapter_set_discov_timeout(adapter,adapter->discov_timeout);/*ignore, this event should not be sent */default:/*ignore, reserved */return;}/*If page scanning gets toggled emit the Pairable property *///这里会发一个property_changed的pairable的signalif((adapter->scan_mode & SCAN_PAGE) != (scan_mode & SCAN_PAGE))emit_property_changed(connection,adapter->path,ADAPTER_INTERFACE,"Pairable",DBUS_TYPE_BOOLEAN,&pairable);if(!discoverable)adapter_set_limited_discoverable(adapter,FALSE);//这里会发一个property_changed的discoverable的signal
 
emit_property_changed(connection,path,ADAPTER_INTERFACE,"Discoverable",DBUS_TYPE_BOOLEAN,&discoverable);adapter->scan_mode= scan_mode;set_mode_complete(adapter);}5.6 WRTIE_SCAN_ENABLE最终引起的状态机的变化在此之前,状态机处于switching的状态,收到了SCAN_MODE_CHANGED的msg。private class Switching extends State {@Overridepublic void enter() {if (DBG) log("Enter Switching:" + getCurrentMessage().what);}@Overridepublic boolean processMessage(Messagemessage) {log("Switching processmessage: " + message.what);boolean retValue = HANDLED;switch(message.what) {case SCAN_MODE_CHANGED:// This event matchesmBluetoothService.switchConnectable action//mPublicState在hotoff到swtiching状态变化时已经被设为STATE_TURNING_ON了,所以这里if没有问题if (mPublicState ==BluetoothAdapter.STATE_TURNING_ON) {// set pairable if it'snot//设置为pairable假如还没有设置的话,这个会先在bluez中检查一下当前是否pairable,我们在前面已经设置好了,所以,这里只是一个检查而已,没有什么实际性的工作
 mBluetoothService.setPairable();//初始化bond state和profile state,这个会在adapter pairable之后,bluetooth turn on之前发生
 mBluetoothService.initBluetoothAfterTurningOn();//这边正式进入到bluetoothon的状态,终于进了这里,哎。。。
 transitionTo(mBluetoothOn);//发送STATE_ON的broadcast
 broadcastState(BluetoothAdapter.STATE_ON);// run bluetooth nowthat it's turned on// Note runBluetoothshould be called only in adapter STATE_ON//连接那些可以自动连接的设备,通知battery,蓝牙打开了
 mBluetoothService.runBluetooth();}break;……
复制代码

 


本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/4980587.html,如需转载请自行联系原作者


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/454182.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

移动端导出excel_连载系列【4】Excel开发移动端quot;APPquot;

前三篇文章介绍了百度地图生成器、源代码编辑器、GPS经纬度批量转换工具、源代码编辑器中添加自定义功能按钮和地图控件。这些写好的Java Script代码虽然可以实现所有期望的结果&#xff0c;但毕竟不是一个HTML文件&#xff0c;不便于传播和使用&#xff0c;更无法变成一个类似…

《操作系统》OS学习(二):启动、中断、异常

Bootloader:加载OS。操作系统一开始是放在DISK&#xff08;硬盘&#xff09;中&#xff0c;并不是放在内存中。 BIOS&#xff1a;基本I/O处理系统。存放在ROMRead-Only Memory&#xff09;只读存储中 BIOS&#xff08;Basic Input/Output System&#xff09;基本输入输出系统。…

常用css属性集(持续更新…)

禁止换行&#xff0c;超出部分显示…&#xff1a;a. 代码&#xff1a;.hide_word{ max-width: 100px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; } b. 效果&#xff1a; 本文转自 bilinyee博客&#xff0c;原文链接&#xff1a; http://blog.51cto.co…

parallels网络初始化失败_33 个神经网络「炼丹」技巧

自然语言处理Andrej Karpathy 是深度学习计算机视觉领域、与领域的研究员。博士期间师从李飞飞。在读博期间&#xff0c;两次在谷歌实习&#xff0c;研究在 Youtube 视频上的大规模特征学习&#xff0c;2015 年在 DeepMind 实习&#xff0c;研究深度强化学习。毕业后&#xff0…

《操作系统》OS学习(三):系统调用

例子 首先看一个标准C库的例子&#xff1a;当我们程序中使用了C库中的printf()函数&#xff0c;实际在底层是在内核态中调用了write()函数。图中右侧则是将程序代码与C库都算到应用程序中&#xff0c;内核提供了一个系统调用接口。 从这个例子我们可以得到以下几点&#xff1a…

JavaScript服务器端开发技术(对象属性的枚举与查询)

既然对象是属性的集合&#xff0c;那么检测与枚举集合中的属性就是一项重要任务。对此&#xff0c;我们来分别看一下ES3和ES5提供的解决方案。 1) ES3枚举方案 示例代码&#xff1a; var contacts{ ID:[0,1,2,3,4,5], names:["Zero","One","Two&q…

treelistview 所有节点失去焦点_垃圾询盘过滤,焦点科技的 Milvus 实践

文章作者&#xff1a;黎阳&#xff0c;焦点科技软件开发工程师李成龙&#xff0c;Zilliz 数据工程师Milvus (https://milvus.io/) 向量搜索引擎开源半年以来&#xff0c;全球已经有数百家企业或组织用户。焦点科技是一家以 B2B 外贸交易为主营业务的科技公司&#xff0c;也是 M…

《操作系统》OS学习(四):计算机体系结构、内存层次和地址生成

计算机除了计算能力之外还有存储能力&#xff0c;存储能力即计算机拥有一系列的存储介质&#xff0c;我们可以在存储介质上存储我们的代码和数据。计算机体系结构中约定了哪些地方可以用来存储数据&#xff1a;CPU内的寄存器、内存和外存。不同的存储介质&#xff0c;容量、速度…

GCC中SIMD指令的应用方法

X86架构上的多媒体应用开发&#xff0c;如果能够使用SIMD指令进行优化&#xff0c; 性能将大大提高。目前&#xff0c;IA-32的SIMD指令包括MMX&#xff0c;SSE&#xff0c;SSE2等几级。 在GCC的开发环境中&#xff0c;有几种使用SIMD指令的方式&#xff0c;本文逐一介绍。X86的…

使用angular4和asp.net core 2 web api做个练习项目(二), 这部分都是angular

上一篇: http://www.cnblogs.com/cgzl/p/7755801.html 完成client.service.ts: import { Injectable } from angular/core; import { Http, Headers } from angular/http; import { Observable } from rxjs/Observable; import { ErrorHandler } from angular/core; import rxj…

leelen可视对讲怎么接线_楼宇对讲系统怎么布线 楼宇对讲系统布线方式【介绍】...

随着智能小区规模不断增加&#xff0c;楼宇可视对讲系统应用越来越广泛&#xff0c;因而视频信号的传输方式与布线设计显得越来越重要。视频信号与数据和音频信号不同&#xff0c;可行的一种传输方式为视频信号基带传输&#xff0c;下面小编就简要介绍一下这种传输方式和布线方…

路由汇总实例

5.2.2.2 路由汇总策略 之前提到过&#xff0c;在网络管理员计划好子网选择并进行预期地路由汇总时&#xff0c;手动路由汇总工作能取得最佳效果。例如&#xff0c;之前的例子设定好了一个考虑周全的计划&#xff0c;管理员只使用远离Yosemite路由器并以10.2开头的子网。这个规定…

《操作系统》OS学习(五):连续内存分配 内存碎片、动态分配、碎片整理、伙伴系统

内存碎片 在没有其他方式辅助的情况下&#xff0c;我们分配给一个进程的内存是连续的。在分配时候我们需要有动态分配与碎片处理。如何理解呢&#xff1f;就是每个进程需要一块内存&#xff0c;我们要选取合适的位置的内存分配给它。当有的进程先结束了内存还给操作系统&#…

世界之窗浏览器删除文本框信息_文本框——Excel里的便利贴

工作表里面的单元格应该是足够我们来记录数据和信息了。但是文本框这个功能在工作表中还是存在&#xff0c;可以理解为便利贴功能。插入文本框1.点击“插入”选项卡。2.然后点击“文本框”。3.在下拉菜单里面&#xff0c;有两种可供选择&#xff1a;横排文本框和垂直文本框。在…

RHEL 5服务篇—常用网络配置命令

常用网络配置命令 在“Linux系统管理”的文章中&#xff0c;大家已经学习了Linux系统的基本管理命令和技巧&#xff0c;为了进一步学习Linux网络服务打下了良好的基础。所以我作者以后将陆续推出Linux网络服务的相关文章。希望大家能给与我大大的支持。 今天我们就来学习一下…

清华大学《操作系统》(六):非连续内存分配 段式、页式、段页式存储管理

背景 连续内存分配给内存分配带来了很多不便&#xff0c;可能所有空闲片区大小都无法满足需求大小&#xff0c;这个分配就会失败。基于这种现状&#xff0c;就有了非连续内存分配的需求。非连续分配成功的几率更高&#xff0c;但也面对更多的问题&#xff0c;比如分配时是不是…

C语言第三次博客作业---单层循环结构

一、PTA实验作业。 题目1 1.实验代码 int n,i; double height1,height2;//1为输入身高&#xff0c;2为输出身高。 char sex; //1<height1<3; //N<1; scanf("%d",&n); while(n--){getchar();scanf("%c%lf",&sex,&height1);switch(sex)…

清华大学《操作系统》(七):虚拟存储、覆盖、交换

接下来几节都是对虚拟存储的讲解。虚拟存储是非连续存储管理的扩展。通过将内存中的数据暂存到外存的方式&#xff0c;为进程提供更大的内存空间。虚拟存储出现的主要原因是因为程序规模的增长速度远远大于存储器容量的增长速度&#xff0c;导致内存空间不够用。其实针对内存空…

遵义大数据中心项目工程概况_市委书记张新文到曹州云都大数据中心等项目现场调研建设情况...

4月25日&#xff0c;市委书记张新文到曹县调研重点项目建设情况&#xff0c;研究推进措施。市委常委、秘书长任仲义参加活动。张新文首先来到曹州云都大数据中心项目建设现场&#xff0c;查看项目推进情况。曹州云都大数据中心&#xff0c;是涵盖云计算区、研发办公区、公寓生活…

linux 可执行文件的分析(gcc GUN BUILEIN)

1、GCC The History of GCC 1984年&#xff0c;Richard Stallman发起了自由软件运动&#xff0c;GNU (Gnus Not Unix)项目应运而生&#xff0c;3年后&#xff0c;最初版的GCC横空出世&#xff0c;成为第一款可移植、可优化、支持ANSI C的开源C编译器。GCC最初的全名是GNU C Com…