6.0的蓝牙已经开发完毕,因为可以得到系统6.0的jar包,so也就开发的快些,更好些。4.4因为代码部分在setting模块里,部分在系统中,so不方便打成jar包。所以就通过广播接受改变状态之类的。也算鼓捣出来一款。

4.4蓝牙效果

开发的思路:

1.开关蓝牙

2.扫描到蓝牙列表和得到配对列表

下面关于连接蓝牙:

A2dp:这个是蓝牙音频传输协议

AVRCP:输入设备控制协议

首先要弄清当前蓝牙的功能属于那种协议,具体代码判断协议的方法不清楚。(本项目用不到)

3.连接蓝牙

4.断开蓝牙与取消配对

1.开关蓝牙

   /*** 打开蓝牙or关闭蓝牙* @param flag true:open*/public void openOrCloseBluetooth(boolean flag) {if (flag) {mBluetoothAdapter.enable();} else {mBluetoothAdapter.disable();}}

2.扫描到蓝牙列表和得到配对列表

扫描蓝牙

//开始扫描public void startScan() {if (mBluetoothAdapter != null) {// scanResultList.clear();if (mBluetoothAdapter.isDiscovering()) {Log.d(TAG, "startScan: cancelDiscovery");mBluetoothAdapter.cancelDiscovery();}mBluetoothAdapter.startDiscovery();Log.d(TAG, "startScan: 开始扫描周围蓝牙");} else {Log.d(TAG, "startScan: 扫描周围蓝牙异常");}}

扫描之后如何获取扫描结果主要通过广播获取

  private void registerBluetoothBroadcastReceiver(Context context) {IntentFilter filter = new IntentFilter();filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//蓝牙状态改变的广播filter.addAction(BluetoothDevice.ACTION_FOUND);//找到设备的广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索完成的广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//开始扫描的广播filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//状态改变filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);if (mReceiver == null) {mReceiver = new BluetoothBroadCasteReceiver();}Log.d(TAG, "registerBluetoothBroadcastReceiver: 注册蓝牙广播" + mBluetoothAdapter.isEnabled());context.registerReceiver(mReceiver, filter);}

接受器中主要处理这三个状态

                case BluetoothAdapter.ACTION_DISCOVERY_STARTED:Log.d(TAG, "onReceive: 开始扫描。");break;case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:Log.d(TAG, "onReceive: 扫描结束。");if (callBack != null) {//callBack.scan_result(scanResultList,            getHasConnectBlueDevices());callBack.scanEnd();}break;case BluetoothDevice.ACTION_CLASS_CHANGED:Log.d(TAG, "onReceive: 一个已经改变的远程设备的蓝牙类。");break;case BluetoothDevice.ACTION_FOUND:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);BluetoothDeviceBean bluetoothDeviceBean = new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_NONE);if (device != null) {//发现的设备统一给一个未配对的状态if (callBack != null) {callBack.foundDevice(bluetoothDeviceBean, getHasConnectBlueDevices());}Log.d(TAG, "onReceive: 远程设备发现。" + device.getName() + "??" + device.getAddress() + "???" + device.getBondState());}break;

tips:

1.扫描蓝牙的时候,扫描结束的广播等待时间较长,为了页面体验就在发现设备的广播中,做数据的收集,但注意的是同一个设备会多次被发现,所以数据要做一些扁平化处理

2.扫描的结果也包含了已经配对的,so数据应该做一些处理

获得已经配对的列表

 /*** 获得已经配对的蓝牙列表* @return*/public Set<BluetoothDeviceBean> getHasConnectBlueDevices() {Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();Set<BluetoothDeviceBean> bluetoothDeviceBeans = new LinkedHashSet<>();if (bondedDevices != null) {for (BluetoothDevice de :bondedDevices) {bluetoothDeviceBeans.add(new BluetoothDeviceBean(de, Bluetooth_State.State_BOND_BONDED));}Log.e(TAG, "getHasConnectBlueDevices: 已经配对的蓝牙设备" + bluetoothDeviceBeans.toString());return bluetoothDeviceBeans;} else {Log.e(TAG, "没有已经配对的蓝牙设备");return bluetoothDeviceBeans;}}

tips:已经配对的列表中及时当前的设备没有连接也会显示。

3.连接蓝牙

连接蓝牙主要分为两部分,一部分是配对,配对完成后再连接

配对:

 /*** 蓝牙配对* @param btClass* @param btDevice*/public void createBond(Class btClass, BluetoothDevice btDevice) {Method createBondMethod = null;try {createBondMethod = btClass.getMethod("createBond");Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);} catch (NoSuchMethodException e) {e.printStackTrace();Log.d(TAG, "createBond: XXXX");} catch (IllegalAccessException e) {e.printStackTrace();Log.d(TAG, "createBond: XXXX1");} catch (InvocationTargetException e) {Log.d(TAG, "createBond: XXXX2");e.printStackTrace();}}

在广播中得到配对的状态:

               case BluetoothDevice.ACTION_BOND_STATE_CHANGED:int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);switch (state) {case BluetoothDevice.BOND_NONE:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BOND_NONE 删除配对" + device.getName());if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_NONE));}break;case BluetoothDevice.BOND_BONDING:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BOND_BONDING 正在配对" + device.getName());if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_BONDING));}break;case BluetoothDevice.BOND_BONDED:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BOND_BONDED 配对成功" + device.getName());if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_BONDED));}//连接操作conectBluetoothDevice(device);break;}break;

收到配对成功的广播进行连接:

A2dp连接:

 //连接蓝牙public void conectBluetoothDevice(BluetoothDevice device) {if (mA2dpService != null) {try {Log.d(TAG, "createBond: 配对成功开始连接");mA2dpService.connect(device);} catch (RemoteException e) {e.printStackTrace();}}}

输入控制设备的连接:

 /*** * @param device* @param isConnect true:连接 false:断开*/private void connectOrDisConnectHidBT(BluetoothDevice device, boolean isConnect) {if (mHidService != null) {//连接try {String flag = "";if (isConnect) {flag = "connect";} else {flag = "disconnect";}if (mHidService.getProfile() == getInputDeviceHiddenConstant()) {if (device != null) {//得到BluetoothInputDevice然后反射connect连接设备Method method = mHidService.getProxy().getClass().getMethod(flag,new Class[]{BluetoothDevice.class});method.invoke(mHidService.getProxy(), device);}}} catch (Exception e) {// TODO Auto-generated catch block// e.printStackTrace();}}}
 /*** 获取BluetoothProfile中hid的profile,"INPUT_DEVICE"类型隐藏,需反射获取* @return*/@SuppressLint("NewApi")public static int getInputDeviceHiddenConstant() {Class<BluetoothProfile> clazz = BluetoothProfile.class;for (Field f : clazz.getFields()) {int mod = f.getModifiers();if (Modifier.isStatic(mod) && Modifier.isPublic(mod)&& Modifier.isFinal(mod)) {try {if (f.getName().equals("INPUT_DEVICE")) {return f.getInt(null);}} catch (Exception e) {}}}return -1;}

tips:连接蓝牙的时候,需要开启一个服务,通过广播接受来判定是否连接成功

A2dp的服务:

    private void initA2dpService() {Intent i = new Intent(IBluetoothA2dp.class.getName());context.bindService(i, mConnection, Context.BIND_AUTO_CREATE);}IBluetoothA2dp mA2dpService;public ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {try {mA2dpService = IBluetoothA2dp.Stub.asInterface(service);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stub}};
               case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:switch (intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, -1)) {case BluetoothA2dp.STATE_CONNECTING:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BluetoothA2dp.STATE_CONNECTING: " + device.getName() + " connecting");if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_CONNECTING));}break;case BluetoothA2dp.STATE_CONNECTED:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if (device != null) {if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_CONNECTED));}Log.d(TAG, "BluetoothA2dp.STATE_CONNECTED: " + device.getName() + " 连接成功");}break;case BluetoothA2dp.STATE_DISCONNECTING:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BluetoothA2dp.STATE_DISCONNECTING: " + device.getName() + " connecting");break;case BluetoothA2dp.STATE_DISCONNECTED:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_DISCONNECTED));}Log.d(TAG, "BluetoothA2dp.STATE_DISCONNECTED: " + device.getName() + " disconnected");break;}break;

输入控制设备:

 //判断连接hid设备的服务是否连上private BTHidServiceBean mHidService = null;/*** 查看BluetoothInputDevice源码,connect(BluetoothDevice device)该方法可以连接HID设备,但是查看BluetoothInputDevice这个类* 是隐藏类,无法直接使用,必须先通过BluetoothProfile.ServiceListener回调得到BluetoothInputDevice,然后再反射connect方法连接*/private BluetoothProfile.ServiceListener connect = new BluetoothProfile.ServiceListener() {@Overridepublic void onServiceConnected(int profile, BluetoothProfile proxy) {//BluetoothProfile proxy这个已经是BluetoothInputDevice类型了mHidService = new BTHidServiceBean(profile, proxy);}@Overridepublic void onServiceDisconnected(int profile) {}};
 /*** 注册输入设备的服务*/private void initHidService() {mBluetoothAdapter.getProfileProxy(context, connect, getInputDeviceHiddenConstant());}

监听连接的广播:

 private void registerBluetoothBroadcastReceiver(Context context) {IntentFilter filter = new IntentFilter();filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//蓝牙状态改变的广播filter.addAction(BluetoothDevice.ACTION_FOUND);//找到设备的广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索完成的广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//开始扫描的广播filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//状态改变filter.addAction("android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED");if (mReceiver == null) {mReceiver = new BluetoothBroadCasteReceiver();}Log.d(TAG, "registerBluetoothBroadcastReceiver: 注册蓝牙广播" + mBluetoothAdapter.isEnabled());context.registerReceiver(mReceiver, filter);}
 case "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED":switch (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0)) {case BluetoothProfile.STATE_CONNECTING:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BluetoothProfile.STATE_CONNECTING: " + device.getName() + " connecting");if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_CONNECTING));}break;case BluetoothProfile.STATE_CONNECTED:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if (device != null) {if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_CONNECTED));}Log.d(TAG, "BluetoothProfile.STATE_CONNECTED: " + device.getName() + " connecting");}break;case BluetoothProfile.STATE_DISCONNECTING:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BluetoothProfile.STATE_DISCONNECTING: " + device.getName() + " connecting");break;case BluetoothProfile.STATE_DISCONNECTED:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_DISCONNECTED));}Log.d(TAG, "BluetoothProfile.STATE_DISCONNECTED: " + device.getName() + " disconnected");break;}break;

附上如何判定蓝牙是否连接成功:

A2dp:

 /*** 判断蓝牙是否已经* @param device* @return*/public boolean isHasConnected(BluetoothDevice device) {try {if (mA2dpService.getConnectionState(device) == BluetoothA2dp.STATE_CONNECTED) {Log.e(TAG, "isHasConnected: XXX1::" + device.getName() + "???" + mA2dpService.getConnectionState(device));return true;} else {Log.e(TAG, "isHasConnected: XXX2::" + device.getName() + "???" + mA2dpService.getConnectionState(device));}} catch (RemoteException e) {e.printStackTrace();}return false;}

输入设备:

//判断蓝牙是否已经public boolean isHasConnected(BluetoothDevice device) {if (mHidService != null) {BluetoothProfile proxy = mHidService.getProxy();int connectionState = proxy.getConnectionState(device);if (connectionState == BluetoothProfile.STATE_CONNECTED) {return true;}}return false;}

4.断开蓝牙与取消配对

断开蓝牙不等于取消配对

A2dp

   /*** 断开蓝牙连接* @param device*/public void disConectBluetoothDevice(BluetoothDevice device) {if (isHasConnected(device) && mA2dpService != null) {try {mA2dpService.disconnect(device);} catch (RemoteException e) {e.printStackTrace();}}}

取消配对一定包含断开蓝牙

 /*** 清除配对历史* @param device*/public void unpairDevice(BluetoothDevice device) {try {Method m = device.getClass().getMethod("removeBond", (Class[]) null);m.invoke(device, (Object[]) null);} catch (Exception e) {Log.d(TAG, "清除配对异常" + e.getMessage());}}
 /*** @param currentDevice* @param isUnpairDevice 是否取消配对*/public void disconnect(BluetoothDevice currentDevice, boolean isUnpairDevice) {Set<BluetoothDeviceBean> hasConnectBlueDevices = helper.getHasConnectBlueDevices();if (hasConnectBlueDevices != null) {for (BluetoothDeviceBean di :hasConnectBlueDevices) {if (di.getDevice().getAddress().equals(currentDevice.getAddress())) {helper.disConectBluetoothDevice(di.getDevice());if (isUnpairDevice) {helper.unpairDevice(di.getDevice());}break;}}}}

输入设备:

配对方法是固定的,断开连接上面已经总结

附件1:4.4蓝牙A2dp工具类:

package com.ygjy.setting4_0.bluetooth.uitls;import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.IBluetoothA2dp;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;import com.ygjy.setting4_0.bluetooth.bean.BluetoothDeviceBean;
import com.ygjy.setting4_0.bluetooth.bean.Bluetooth_State;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;/*** @创建人:hcy* @创建时间:2018/11/9* @作用描述:Function**/
public class BlueToothHelper {private static final String TAG = "BlueToothHelper>>>";private BluetoothManager mBluetoothManager;private BluetoothAdapter mBluetoothAdapter;//private Set<BluetoothDeviceBean> scanResultList;private Context context;public BlueToothHelper(Context context) {//获得蓝牙管理对象this.context = context;mBluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);//获得蓝牙适配器mBluetoothAdapter = mBluetoothManager.getAdapter();//scanResultList = new LinkedHashSet<>();if (hasBluetooth()) {initA2dpService();registerBluetoothBroadcastReceiver(context);} else {Toast.makeText(context, "当前设备不支持蓝牙", Toast.LENGTH_SHORT).show();}}/*** 设备是否支持蓝牙** @return true:支持 false:不支持*/public boolean hasBluetooth() {if (mBluetoothAdapter != null) {Log.d(TAG, "该设备支持蓝牙:本机的蓝牙名称" + mBluetoothAdapter.getName());return true;} else {Log.d(TAG, "该设备不支持蓝牙");}return false;}private BroadcastReceiver mReceiver;/*** 注册广播可以获取扫描结果和配对的状态* @param context*/private void registerBluetoothBroadcastReceiver(Context context) {IntentFilter filter = new IntentFilter();filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//蓝牙状态改变的广播filter.addAction(BluetoothDevice.ACTION_FOUND);//找到设备的广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索完成的广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//开始扫描的广播filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//状态改变filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);if (mReceiver == null) {mReceiver = new BluetoothBroadCasteReceiver();}Log.d(TAG, "registerBluetoothBroadcastReceiver: 注册蓝牙广播" + mBluetoothAdapter.isEnabled());context.registerReceiver(mReceiver, filter);}public void unregisterBluetoothBroadCastReceiver(Context context) {if (mBluetoothAdapter != null) {mBluetoothAdapter.cancelDiscovery();}if (mA2dpService != null) {context.unbindService(mConnection);}if (mReceiver != null) {context.unregisterReceiver(mReceiver);}}//开始扫描public void startScan() {if (mBluetoothAdapter != null) {// scanResultList.clear();if (mBluetoothAdapter.isDiscovering()) {Log.d(TAG, "startScan: cancelDiscovery");mBluetoothAdapter.cancelDiscovery();}mBluetoothAdapter.startDiscovery();Log.d(TAG, "startScan: 开始扫描周围蓝牙");} else {Log.d(TAG, "startScan: 扫描周围蓝牙异常");}}//判断蓝牙是否已经开启public boolean isEnabled() {boolean bluetooth_state = mBluetoothAdapter.isEnabled();Log.d(TAG, "isEnabled: 蓝牙当前是否开启::" + bluetooth_state);return bluetooth_state;}/*** 打开蓝牙or关闭蓝牙* @param flag true:open*/public void openOrCloseBluetooth(boolean flag) {if (flag) {mBluetoothAdapter.enable();} else {mBluetoothAdapter.disable();}}//蓝牙的广播public class BluetoothBroadCasteReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();BluetoothDevice device = null;switch (action) {case BluetoothAdapter.ACTION_DISCOVERY_STARTED:Log.d(TAG, "onReceive: 开始扫描。");break;case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:Log.d(TAG, "onReceive: 扫描结束。");if (callBack != null) {//callBack.scan_result(scanResultList, getHasConnectBlueDevices());callBack.scanEnd();}break;case BluetoothDevice.ACTION_CLASS_CHANGED:Log.d(TAG, "onReceive: 一个已经改变的远程设备的蓝牙类。");break;case BluetoothDevice.ACTION_FOUND:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);BluetoothDeviceBean bluetoothDeviceBean = new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_NONE);if (device != null) {//发现的设备统一给一个未配对的状态if (callBack != null) {callBack.foundDevice(bluetoothDeviceBean, getHasConnectBlueDevices());}Log.d(TAG, "onReceive: 远程设备发现。" + device.getName() + "??" + device.getAddress() + "???" + device.getBondState());}break;case BluetoothDevice.ACTION_BOND_STATE_CHANGED:int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);switch (state) {case BluetoothDevice.BOND_NONE:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BOND_NONE 删除配对" + device.getName());if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_NONE));}break;case BluetoothDevice.BOND_BONDING:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BOND_BONDING 正在配对" + device.getName());if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_BONDING));}break;case BluetoothDevice.BOND_BONDED:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BOND_BONDED 配对成功" + device.getName());if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_BONDED));}//连接操作conectBluetoothDevice(device);break;}break;case BluetoothAdapter.ACTION_STATE_CHANGED:int blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);switch (blueState) {case BluetoothAdapter.STATE_TURNING_ON:break;case BluetoothAdapter.STATE_ON:Log.d(TAG, "onReceives: 蓝牙已经打开");if (callBack != null) {callBack.bluetooth_openOrClose(true);}break;case BluetoothAdapter.STATE_TURNING_OFF:break;case BluetoothAdapter.STATE_OFF:Log.d(TAG, "onReceives: 蓝牙已经关闭");if (callBack != null) {callBack.bluetooth_openOrClose(false);}break;}break;case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:switch (intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, -1)) {case BluetoothA2dp.STATE_CONNECTING:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BluetoothA2dp.STATE_CONNECTING: " + device.getName() + " connecting");if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_CONNECTING));}break;case BluetoothA2dp.STATE_CONNECTED:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if (device != null) {if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_CONNECTED));}Log.d(TAG, "BluetoothA2dp.STATE_CONNECTED: " + device.getName() + " 连接成功");}break;case BluetoothA2dp.STATE_DISCONNECTING:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BluetoothA2dp.STATE_DISCONNECTING: " + device.getName() + " connecting");break;case BluetoothA2dp.STATE_DISCONNECTED:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_DISCONNECTED));}Log.d(TAG, "BluetoothA2dp.STATE_DISCONNECTED: " + device.getName() + " disconnected");break;}break;}}}//连接蓝牙public void conectBluetoothDevice(BluetoothDevice device) {if (mA2dpService != null) {try {Log.d(TAG, "createBond: 配对成功开始连接");mA2dpService.connect(device);} catch (RemoteException e) {e.printStackTrace();}}}/*** 断开蓝牙连接* @param device*/public void disConectBluetoothDevice(BluetoothDevice device) {if (isHasConnected(device) && mA2dpService != null) {try {mA2dpService.disconnect(device);} catch (RemoteException e) {e.printStackTrace();}}}public interface BuletoothCallBack {void foundDevice(BluetoothDeviceBean deviceBean, Set<BluetoothDeviceBean> hasBoundSet);void scan_result(Set<BluetoothDeviceBean> list, Set<BluetoothDeviceBean> hasBoundSet);void scanEnd();void bluetooth_openOrClose(boolean b);void update_state(BluetoothDeviceBean deviceBean);}private BuletoothCallBack callBack;public void setCallBack(BuletoothCallBack callBack) {this.callBack = callBack;}public boolean isConnectedAddress(BluetoothDevice _b) {BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();Class<BluetoothAdapter> bluetoothAdapterClass = BluetoothAdapter.class;//得到BluetoothAdapter的Class对象try {//得到蓝牙状态的方法Method method = bluetoothAdapterClass.getDeclaredMethod("getConnectionState", (Class[]) null);//打开权限method.setAccessible(true);int state = (int) method.invoke(bluetoothAdapter, (Object[]) null);if (state == BluetoothAdapter.STATE_CONNECTED) {Log.i(TAG, "BluetoothAdapter.STATE_CONNECTED");Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();Log.i(TAG, "devices:" + devices.size());for (BluetoothDevice device : devices) {Method isConnectedMethod = BluetoothDevice.class.getDeclaredMethod("isConnected", (Class[]) null);method.setAccessible(true);boolean isConnected = (boolean) isConnectedMethod.invoke(device, (Object[]) null);if (isConnected) {Log.i(TAG, "connected:" + device.getAddress());if (getAddress(_b).equals(device.getAddress())) {return true;}}}}} catch (Exception e) {e.printStackTrace();}return false;}public String getAddress(BluetoothDevice device) {return device.getAddress();}/*** 获得已经配对的蓝牙列表* @return*/public Set<BluetoothDeviceBean> getHasConnectBlueDevices() {Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();Set<BluetoothDeviceBean> bluetoothDeviceBeans = new LinkedHashSet<>();if (bondedDevices != null) {for (BluetoothDevice de :bondedDevices) {bluetoothDeviceBeans.add(new BluetoothDeviceBean(de, Bluetooth_State.State_BOND_BONDED));}Log.e(TAG, "getHasConnectBlueDevices: 已经配对的蓝牙设备" + bluetoothDeviceBeans.toString());return bluetoothDeviceBeans;} else {Log.e(TAG, "没有已经配对的蓝牙设备");return bluetoothDeviceBeans;}}/*** 清除配对历史* @param device*/public void unpairDevice(BluetoothDevice device) {try {Method m = device.getClass().getMethod("removeBond", (Class[]) null);m.invoke(device, (Object[]) null);} catch (Exception e) {Log.d(TAG, "清除配对异常" + e.getMessage());}}/*** 蓝牙配对* @param btClass* @param btDevice*/public void createBond(Class btClass, BluetoothDevice btDevice) {Method createBondMethod = null;try {createBondMethod = btClass.getMethod("createBond");Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);} catch (NoSuchMethodException e) {e.printStackTrace();Log.d(TAG, "createBond: XXXX");} catch (IllegalAccessException e) {e.printStackTrace();Log.d(TAG, "createBond: XXXX1");} catch (InvocationTargetException e) {Log.d(TAG, "createBond: XXXX2");e.printStackTrace();}}private void initA2dpService() {Intent i = new Intent(IBluetoothA2dp.class.getName());context.bindService(i, mConnection, Context.BIND_AUTO_CREATE);}IBluetoothA2dp mA2dpService;public ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {try {mA2dpService = IBluetoothA2dp.Stub.asInterface(service);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stub}};public Intent getExplicitIntent(Context context, Intent implicitIntent) {// Retrieve all services that can match the given intentPackageManager pm = context.getPackageManager();List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);// Make sure only one match was foundif (resolveInfo == null || resolveInfo.size() != 1) {return null;}// Get component info and create ComponentNameResolveInfo serviceInfo = resolveInfo.get(0);String packageName = serviceInfo.serviceInfo.packageName;String className = serviceInfo.serviceInfo.name;ComponentName component = new ComponentName(packageName, className);// Create a new intent. Use the old one for extras and such reuseIntent explicitIntent = new Intent(implicitIntent);// Set the component to be explicitexplicitIntent.setComponent(component);return explicitIntent;}/*** 判断蓝牙是否已经* @param device* @return*/public boolean isHasConnected(BluetoothDevice device) {try {if (mA2dpService.getConnectionState(device) == BluetoothA2dp.STATE_CONNECTED) {Log.e(TAG, "isHasConnected: XXX1::" + device.getName() + "???" + mA2dpService.getConnectionState(device));return true;} else {Log.e(TAG, "isHasConnected: XXX2::" + device.getName() + "???" + mA2dpService.getConnectionState(device));}} catch (RemoteException e) {e.printStackTrace();}return false;}
}

附件2:蓝牙输入控制设备的工具类:

package com.ygjy.setting4_0.bluetooth.uitls;import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.widget.Toast;import com.ygjy.setting4_0.bluetooth.bean.BTHidServiceBean;
import com.ygjy.setting4_0.bluetooth.bean.BluetoothDeviceBean;
import com.ygjy.setting4_0.bluetooth.bean.Bluetooth_State;import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.LinkedHashSet;
import java.util.Set;/*** @创建人:hcy* @创建时间:2018/11/9* @作用描述:Function**/
public class BlueToothHelper {private static final String TAG = "BlueToothHelper>>>";private BluetoothManager mBluetoothManager;private BluetoothAdapter mBluetoothAdapter;//private Set<BluetoothDeviceBean> scanResultList;private Context context;BluetoothDevice device = null;public BlueToothHelper(Context context) {//获得蓝牙管理对象this.context = context;mBluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);//获得蓝牙适配器mBluetoothAdapter = mBluetoothManager.getAdapter();//scanResultList = new LinkedHashSet<>();if (hasBluetooth()) {initHidService();registerBluetoothBroadcastReceiver(context);} else {Toast.makeText(context, "当前设备不支持蓝牙", Toast.LENGTH_SHORT).show();}}/*** 设备是否支持蓝牙** @return true:支持 false:不支持*/public boolean hasBluetooth() {if (mBluetoothAdapter != null) {Log.d(TAG, "该设备支持蓝牙:本机的蓝牙名称" + mBluetoothAdapter.getName());return true;} else {Log.d(TAG, "该设备不支持蓝牙");}return false;}private BroadcastReceiver mReceiver;private void registerBluetoothBroadcastReceiver(Context context) {IntentFilter filter = new IntentFilter();filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//蓝牙状态改变的广播filter.addAction(BluetoothDevice.ACTION_FOUND);//找到设备的广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索完成的广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//开始扫描的广播filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//状态改变filter.addAction("android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED");if (mReceiver == null) {mReceiver = new BluetoothBroadCasteReceiver();}Log.d(TAG, "registerBluetoothBroadcastReceiver: 注册蓝牙广播" + mBluetoothAdapter.isEnabled());context.registerReceiver(mReceiver, filter);}public void unregisterBluetoothBroadCastReceiver(Context context) {if (mBluetoothAdapter != null) {mBluetoothAdapter.cancelDiscovery();}
//        if (mA2dpService != null) {
//            context.unbindService(mConnection);
//        }if (mReceiver != null) {context.unregisterReceiver(mReceiver);}}//开始扫描public void startScan() {if (mBluetoothAdapter != null) {// scanResultList.clear();if (mBluetoothAdapter.isDiscovering()) {Log.d(TAG, "startScan: cancelDiscovery");mBluetoothAdapter.cancelDiscovery();}mBluetoothAdapter.startDiscovery();Log.d(TAG, "startScan: 开始扫描周围蓝牙");} else {Log.d(TAG, "startScan: 扫描周围蓝牙异常");}}//判断蓝牙是否已经开启public boolean isEnabled() {boolean bluetooth_state = mBluetoothAdapter.isEnabled();Log.d(TAG, "isEnabled: 蓝牙当前是否开启::" + bluetooth_state);return bluetooth_state;}public void openOrCloseBluetooth(boolean flag) {if (flag) {mBluetoothAdapter.enable();} else {mBluetoothAdapter.disable();}}//蓝牙的广播public class BluetoothBroadCasteReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();switch (action) {case BluetoothAdapter.ACTION_DISCOVERY_STARTED:Log.d(TAG, "onReceive: 开始扫描。");break;case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:if (callBack != null) {//callBack.scan_result(scanResultList, getHasConnectBlueDevices());callBack.scanEnd();}break;case BluetoothDevice.ACTION_CLASS_CHANGED:Log.d(TAG, "onReceive: 一个已经改变的远程设备的蓝牙类。");break;case BluetoothDevice.ACTION_FOUND:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);BluetoothDeviceBean bluetoothDeviceBean = new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_NONE);if (device != null) {//发现的设备统一给一个未配对的状态if (callBack != null) {callBack.foundDevice(bluetoothDeviceBean, getHasConnectBlueDevices());}Log.d(TAG, "onReceive: 远程设备发现。" + device.getName() + "??" + device.getAddress() + "???" + device.getBondState());}break;case BluetoothDevice.ACTION_BOND_STATE_CHANGED:int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);switch (state) {case BluetoothDevice.BOND_NONE:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BOND_NONE 删除配对" + device.getName());if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_NONE));}break;case BluetoothDevice.BOND_BONDING:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BOND_BONDING 正在配对" + device.getName());if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_BONDING));}break;case BluetoothDevice.BOND_BONDED:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BOND_BONDED 配对成功" + device.getName());if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.State_BOND_BONDED));}conectBluetoothDevice(device);break;}break;case BluetoothAdapter.ACTION_STATE_CHANGED:int blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);switch (blueState) {case BluetoothAdapter.STATE_TURNING_ON:break;case BluetoothAdapter.STATE_ON:Log.d(TAG, "onReceives: 蓝牙已经打开");if (callBack != null) {callBack.bluetooth_openOrClose(true);}break;case BluetoothAdapter.STATE_TURNING_OFF:break;case BluetoothAdapter.STATE_OFF:Log.d(TAG, "onReceives: 蓝牙已经关闭");if (callBack != null) {callBack.bluetooth_openOrClose(false);}break;}break;case "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED":switch (intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0)) {case BluetoothProfile.STATE_CONNECTING:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BluetoothProfile.STATE_CONNECTING: " + device.getName() + " connecting");if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_CONNECTING));}break;case BluetoothProfile.STATE_CONNECTED:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if (device != null) {if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_CONNECTED));}Log.d(TAG, "BluetoothProfile.STATE_CONNECTED: " + device.getName() + " connecting");}break;case BluetoothProfile.STATE_DISCONNECTING:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);Log.d(TAG, "BluetoothProfile.STATE_DISCONNECTING: " + device.getName() + " connecting");break;case BluetoothProfile.STATE_DISCONNECTED:device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if (callBack != null) {callBack.update_state(new BluetoothDeviceBean(device, Bluetooth_State.STATE_DISCONNECTED));}Log.d(TAG, "BluetoothProfile.STATE_DISCONNECTED: " + device.getName() + " disconnected");break;}break;}}}//连接蓝牙public void conectBluetoothDevice(BluetoothDevice device) {connectOrDisConnectHidBT(device, true);}/**** @param device* @param isConnect true:连接 false:断开*/private void connectOrDisConnectHidBT(BluetoothDevice device, boolean isConnect) {if (mHidService != null) {//连接try {String flag = "";if (isConnect) {flag = "connect";} else {flag = "disconnect";}if (mHidService.getProfile() == getInputDeviceHiddenConstant()) {if (device != null) {//得到BluetoothInputDevice然后反射connect连接设备Method method = mHidService.getProxy().getClass().getMethod(flag,new Class[]{BluetoothDevice.class});method.invoke(mHidService.getProxy(), device);}}} catch (Exception e) {// TODO Auto-generated catch block// e.printStackTrace();}}}public void disConectBluetoothDevice(BluetoothDevice device) {if (isHasConnected(device)) {//如果设备连接就让他断开连接connectOrDisConnectHidBT(device, false);}}//判断连接hid设备的服务是否连上private BTHidServiceBean mHidService = null;/*** 查看BluetoothInputDevice源码,connect(BluetoothDevice device)该方法可以连接HID设备,但是查看BluetoothInputDevice这个类* 是隐藏类,无法直接使用,必须先通过BluetoothProfile.ServiceListener回调得到BluetoothInputDevice,然后再反射connect方法连接*/private BluetoothProfile.ServiceListener connect = new BluetoothProfile.ServiceListener() {@Overridepublic void onServiceConnected(int profile, BluetoothProfile proxy) {//BluetoothProfile proxy这个已经是BluetoothInputDevice类型了mHidService = new BTHidServiceBean(profile, proxy);}@Overridepublic void onServiceDisconnected(int profile) {}};/*** 获取BluetoothProfile中hid的profile,"INPUT_DEVICE"类型隐藏,需反射获取* @return*/@SuppressLint("NewApi")public static int getInputDeviceHiddenConstant() {Class<BluetoothProfile> clazz = BluetoothProfile.class;for (Field f : clazz.getFields()) {int mod = f.getModifiers();if (Modifier.isStatic(mod) && Modifier.isPublic(mod)&& Modifier.isFinal(mod)) {try {if (f.getName().equals("INPUT_DEVICE")) {return f.getInt(null);}} catch (Exception e) {}}}return -1;}public interface BuletoothCallBack {void foundDevice(BluetoothDeviceBean deviceBean, Set<BluetoothDeviceBean> hasBoundSet);void scan_result(Set<BluetoothDeviceBean> list, Set<BluetoothDeviceBean> hasBoundSet);void scanEnd();void bluetooth_openOrClose(boolean b);void update_state(BluetoothDeviceBean deviceBean);}private BuletoothCallBack callBack;public void setCallBack(BuletoothCallBack callBack) {this.callBack = callBack;}public boolean isConnectedAddress(BluetoothDevice _b) {BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();Class<BluetoothAdapter> bluetoothAdapterClass = BluetoothAdapter.class;//得到BluetoothAdapter的Class对象try {//得到蓝牙状态的方法Method method = bluetoothAdapterClass.getDeclaredMethod("getConnectionState", (Class[]) null);//打开权限method.setAccessible(true);int state = (int) method.invoke(bluetoothAdapter, (Object[]) null);if (state == BluetoothAdapter.STATE_CONNECTED) {Log.i(TAG, "BluetoothAdapter.STATE_CONNECTED");Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();Log.i(TAG, "devices:" + devices.size());for (BluetoothDevice device : devices) {Method isConnectedMethod = BluetoothDevice.class.getDeclaredMethod("isConnected", (Class[]) null);method.setAccessible(true);boolean isConnected = (boolean) isConnectedMethod.invoke(device, (Object[]) null);if (isConnected) {Log.i(TAG, "connected:" + device.getAddress());if (getAddress(_b).equals(device.getAddress())) {return true;}}}}} catch (Exception e) {e.printStackTrace();}return false;}public String getAddress(BluetoothDevice device) {return device.getAddress();}public Set<BluetoothDeviceBean> getHasConnectBlueDevices() {Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();Set<BluetoothDeviceBean> bluetoothDeviceBeans = new LinkedHashSet<>();if (bondedDevices != null) {for (BluetoothDevice de :bondedDevices) {bluetoothDeviceBeans.add(new BluetoothDeviceBean(de, Bluetooth_State.State_BOND_BONDED));}Log.e(TAG, "getHasConnectBlueDevices: 已经配对的蓝牙设备" + bluetoothDeviceBeans.toString());return bluetoothDeviceBeans;} else {Log.e(TAG, "没有已经配对的蓝牙设备");return bluetoothDeviceBeans;}}//清除配对历史public void unpairDevice(BluetoothDevice device) {try {Method m = device.getClass().getMethod("removeBond", (Class[]) null);m.invoke(device, (Object[]) null);} catch (Exception e) {Log.d(TAG, "清除配对异常" + e.getMessage());}}public void createBond(Class btClass, BluetoothDevice btDevice) {Method createBondMethod = null;try {createBondMethod = btClass.getMethod("createBond");Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);} catch (NoSuchMethodException e) {e.printStackTrace();Log.d(TAG, "createBond: XXXX");} catch (IllegalAccessException e) {e.printStackTrace();Log.d(TAG, "createBond: XXXX1");} catch (InvocationTargetException e) {Log.d(TAG, "createBond: XXXX2");e.printStackTrace();}}/*** 注册输入设备的服务*/private void initHidService() {mBluetoothAdapter.getProfileProxy(context, connect, getInputDeviceHiddenConstant());}//判断蓝牙是否已经public boolean isHasConnected(BluetoothDevice device) {if (mHidService != null) {BluetoothProfile proxy = mHidService.getProxy();int connectionState = proxy.getConnectionState(device);if (connectionState == BluetoothProfile.STATE_CONNECTED) {return true;}}return false;}
}

android 4.4 蓝牙开发总结(电视盒子)相关推荐

  1. android Ble4.0蓝牙开发之搜索慢、startLeScan()过时,6.0以上不需要定位权限也能快速搜索到蓝牙设备

    项目中需要用到android Ble蓝牙4.0开发技术,于是开启了蓝牙填坑之旅,说实话,蓝牙开发坑真多,跳出一个又进入下一个,每次遇到 问题,就觉得不可能解决了,还好在自己的摸索中,都一一的化解了,以 ...

  2. Android BLE低功耗蓝牙开发

    啦啦啦在上一个项目中有用到BLE低功耗蓝牙开发,当时baidu google了很多资料,但大多数都是千篇一律,英文文档我这种渣渣又看不懂...总之刚开始查的很痛苦.所以要把自己的踩坑之路写下来记录下, ...

  3. android o tv shield,最强电视盒子测评:Nvidia Shield TV

    最近有一位远在美国的朋友向我推荐了一款英伟达(Nvidia)在 2015 年推出的客厅娱乐设备:Nvidia Shield TV. 我最初的态度是不屑一顾,毕竟 Shield 刚推出时的卖点是游戏串流 ...

  4. 【Android】BLE 蓝牙开发流程篇

    携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 4 天,点击查看活动详情 前言 本文旨在梳理 BLE 蓝牙开发的主要流程,其中涉及到其他的知识,将会单独成文梳理.如有任何疑问, ...

  5. Android ble covana,Android BLE低功耗蓝牙开发

    最近做了一个智能硬件开发(针灸仪)的项目,有一部分涉及到低功耗蓝牙的开发,就是通过蓝牙和设备进行数据的交互,比如控制改设备的LED的开关,设备的开关机,设置设备的时间和温度等,下面就项目中遇到的坑一一 ...

  6. android低耗能蓝牙开发,Android BLE低功耗蓝牙开发

    最近做了一个智能硬件开发(针灸仪)的项目,有一部分涉及到低功耗蓝牙的开发,就是通过蓝牙和设备进行数据的交互,比如控制改设备的LED的开关,设备的开关机,设置设备的时间和温度等,下面就项目中遇到的坑一一 ...

  7. Android BLE低功耗蓝牙开发(下) BLE客户端(中央设备)与GATT服务的通讯

    之前的文章简单实现了使用传统蓝牙进行通讯的DEMO,说是最简单其实只是夸张的写法~毕竟标题党横行,我们也得学学点~至少没有UC震惊部那么夸张. 然后,本来是要写Android开发之BlueTooth- ...

  8. android中基于蓝牙开发的demo

    今儿闲着无聊,重新浏览android中sdk重的sample中的demo,觉的BluetoothChat写的不错,就把它搬到这里,以方便查看和学习. 主显示界面activity: /** Copyri ...

  9. android nfc 配对蓝牙 开发,NFC和蓝牙两种配对方式_配件评测-中关村在线

    在功能上方面,OVEVO SH03B蓝牙耳机除了支持蓝牙连接之外,还支持NFC(近距离无线通讯技术)功能.用户只需打开手机的NFC功能,与耳机背面的"NFC"字符区域进行对碰即可配 ...

最新文章

  1. eclipse集成mybatis的generater插件
  2. HIDL示例-JAVA服务创建-Client验证-Android10.0 HwBinder通信原理(四)
  3. android python 纠正图片,Python脚本替换Android资源(包名,图片,文件内容)
  4. k8s 查看mysql 日志_k8s 使用 Init Container 确保依赖的服务已经启动
  5. ubuntu切换中文输入法
  6. ffmpeg avformat_open_input返回失败的解决办法
  7. android ndk 智能指针,智能指针与弱引用详解
  8. 【转】Linux下的多线程编程背景知识
  9. 最简单 NDK 样例
  10. 使用IOCP需要注意的一些问题~~(不断补充)
  11. php为什么容易解密,PHP代码的加密和解密
  12. 乘法器的Verilog HDL实现
  13. ubuntu报错 E:无法定位软件包
  14. html5怎么给标题居中,html5标题居中 Html5如何使div里面文字在水平垂直居中对齐...
  15. Linux终端更改字体
  16. 荣耀Magicbook安装黑苹果教程(OpenCore引导)
  17. IMRAM: Iterative Matching with Recurrent Attention Memory for Cross-Modal Image-Text Retrieval
  18. 热烈祝贺联诚发内容科技落户人民网(厦门)内容科技产业园
  19. 与传统招聘方式相比,小程序招聘都有哪些优势?
  20. AG9311/AG9310 Type-C转HDMI设计方案|替代AG9310/AG9311芯片|GSV2201可完全替代兼容AG9310/AG9311

热门文章

  1. puzzle(1321)时间旅人
  2. 【华为OD机试 2023最新 】 最短木板长度(C++ 100%)
  3. linux tig不支持中文,颠覆 Git 命令使用体验的神器 -- tig
  4. Python数据分析与实战挖掘
  5. 树枝学术 | 图书查找、论文查找全攻略
  6. 英汉对照:32个最富哲理的名言警句
  7. 上海公积金销户问题--程序员
  8. L - 芜湖塔台请求起飞
  9. vb.net 简单取摄像头图片_【图片】大车监控如何安装?_大车监控吧
  10. WKWebView加载txt文档乱码