bluetooth le introduced android 4.3, therefore using 2 android devices , both devices supports api version 4.4.2
even, paired both devices, still not showing device in list, see below screenshot

i have tried both ways:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> and
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false"/> log says:
07-16 17:26:15.146 3857-3857/com.example.android.bluetoothlegatt d/dalvikvm﹕ late-enabling checkjni 07-16 17:26:15.146 3857-3857/com.example.android.bluetoothlegatt d/dalvikvm﹕ try disable coredump pid 3857 07-16 17:26:15.146 3857-3857/com.example.android.bluetoothlegatt d/dalvikvm﹕ process 3857 nice name: com.example.android.bluetoothlegatt 07-16 17:26:15.146 3857-3857/com.example.android.bluetoothlegatt d/dalvikvm﹕ options: not specified 07-16 17:26:15.246 3857-3857/com.example.android.bluetoothlegatt d/bluetoothadapter﹕ startlescan(): null 07-16 17:26:15.276 3857-3869/com.example.android.bluetoothlegatt d/bluetoothadapter﹕ onclientregistered() - status=0 clientif=5 07-16 17:26:15.296 3857-3857/com.example.android.bluetoothlegatt e/imgsrv﹕ :0: pvrdrmopen: tp3, ret = 50 07-16 17:26:15.306 3857-3857/com.example.android.bluetoothlegatt e/imgsrv﹕ :0: pvrdrmopen: tp3, ret = 53 07-16 17:26:15.306 3857-3857/com.example.android.bluetoothlegatt e/imgsrv﹕ :0: pvrdrmopen: tp3, ret = 54 07-16 17:26:15.306 3857-3857/com.example.android.bluetoothlegatt e/imgsrv﹕ :0: pvrdrmopen: tp3, ret = 54 07-16 17:26:15.306 3857-3857/com.example.android.bluetoothlegatt e/imgsrv﹕ :0: pvrdrmopen: tp3, ret = 54 07-16 17:26:15.306 3857-3857/com.example.android.bluetoothlegatt e/imgsrv﹕ :0: pvrdrmopen: tp3, ret = 56 07-16 17:26:15.346 3857-3857/com.example.android.bluetoothlegatt d/openglrenderer﹕ enabling debug mode 0 07-16 17:26:25.246 3857-3857/com.example.android.bluetoothlegatt d/bluetoothadapter﹕ stoplescan() code:
bluetoothleservice.java:-
public class bluetoothleservice extends service { ....... public final static uuid uuid_heart_rate_measurement = uuid.fromstring(samplegattattributes.heart_rate_measurement); private final bluetoothgattcallback mgattcallback = new bluetoothgattcallback() { @override public void onconnectionstatechange(bluetoothgatt gatt, int status, int newstate) { string intentaction; if (newstate == bluetoothprofile.state_connected) { intentaction = action_gatt_connected; mconnectionstate = state_connected; broadcastupdate(intentaction); log.i(tag, "connected gatt server."); // attempts discover services after successful connection. log.i(tag, "attempting start service discovery:" + mbluetoothgatt.discoverservices()); } else if (newstate == bluetoothprofile.state_disconnected) { intentaction = action_gatt_disconnected; mconnectionstate = state_disconnected; log.i(tag, "disconnected gatt server."); broadcastupdate(intentaction); } } @override public void onservicesdiscovered(bluetoothgatt gatt, int status) { if (status == bluetoothgatt.gatt_success) { broadcastupdate(action_gatt_services_discovered); } else { log.w(tag, "onservicesdiscovered received: " + status); } } @override public void oncharacteristicread(bluetoothgatt gatt, bluetoothgattcharacteristic characteristic, int status) { if (status == bluetoothgatt.gatt_success) { broadcastupdate(action_data_available, characteristic); } } @override public void oncharacteristicchanged(bluetoothgatt gatt, bluetoothgattcharacteristic characteristic) { broadcastupdate(action_data_available, characteristic); } }; private void broadcastupdate(final string action) { final intent intent = new intent(action); sendbroadcast(intent); } private void broadcastupdate(final string action, final bluetoothgattcharacteristic characteristic) { final intent intent = new intent(action); if (uuid_heart_rate_measurement.equals(characteristic.getuuid())) { int flag = characteristic.getproperties(); int format = -1; if ((flag & 0x01) != 0) { format = bluetoothgattcharacteristic.format_uint16; log.d(tag, "heart rate format uint16."); } else { format = bluetoothgattcharacteristic.format_uint8; log.d(tag, "heart rate format uint8."); } final int heartrate = characteristic.getintvalue(format, 1); log.d(tag, string.format("received heart rate: %d", heartrate)); intent.putextra(extra_data, string.valueof(heartrate)); } else { // other profiles, writes data formatted in hex. final byte[] data = characteristic.getvalue(); if (data != null && data.length > 0) { final stringbuilder stringbuilder = new stringbuilder(data.length); for(byte bytechar : data) stringbuilder.append(string.format("%02x ", bytechar)); intent.putextra(extra_data, new string(data) + "\n" + stringbuilder.tostring()); } } sendbroadcast(intent); } public class localbinder extends binder { bluetoothleservice getservice() { return bluetoothleservice.this; } } @override public ibinder onbind(intent intent) { return mbinder; } @override public boolean onunbind(intent intent) { close(); return super.onunbind(intent); } private final ibinder mbinder = new localbinder(); public boolean initialize() { if (mbluetoothmanager == null) { mbluetoothmanager = (bluetoothmanager) getsystemservice(context.bluetooth_service); if (mbluetoothmanager == null) { log.e(tag, "unable initialize bluetoothmanager."); return false; } } mbluetoothadapter = mbluetoothmanager.getadapter(); if (mbluetoothadapter == null) { log.e(tag, "unable obtain bluetoothadapter."); return false; } return true; } public boolean connect(final string address) { if (mbluetoothadapter == null || address == null) { log.w(tag, "bluetoothadapter not initialized or unspecified address."); return false; } // connected device. try reconnect. if (mbluetoothdeviceaddress != null && address.equals(mbluetoothdeviceaddress) && mbluetoothgatt != null) { log.d(tag, "trying use existing mbluetoothgatt connection."); if (mbluetoothgatt.connect()) { mconnectionstate = state_connecting; return true; } else { return false; } } final bluetoothdevice device = mbluetoothadapter.getremotedevice(address); if (device == null) { log.w(tag, "device not found. unable connect."); return false; } // want directly connect device, setting autoconnect // parameter false. mbluetoothgatt = device.connectgatt(this, false, mgattcallback); log.d(tag, "trying create new connection."); mbluetoothdeviceaddress = address; mconnectionstate = state_connecting; return true; } public void disconnect() { if (mbluetoothadapter == null || mbluetoothgatt == null) { log.w(tag, "bluetoothadapter not initialized"); return; } mbluetoothgatt.disconnect(); } public void close() { if (mbluetoothgatt == null) { return; } mbluetoothgatt.close(); mbluetoothgatt = null; } public void readcharacteristic(bluetoothgattcharacteristic characteristic) { if (mbluetoothadapter == null || mbluetoothgatt == null) { log.w(tag, "bluetoothadapter not initialized"); return; } mbluetoothgatt.readcharacteristic(characteristic); } public void setcharacteristicnotification(bluetoothgattcharacteristic characteristic, boolean enabled) { if (mbluetoothadapter == null || mbluetoothgatt == null) { log.w(tag, "bluetoothadapter not initialized"); return; } mbluetoothgatt.setcharacteristicnotification(characteristic, enabled); // specific heart rate measurement. if (uuid_heart_rate_measurement.equals(characteristic.getuuid())) { bluetoothgattdescriptor descriptor = characteristic.getdescriptor( uuid.fromstring(samplegattattributes.client_characteristic_config)); descriptor.setvalue(bluetoothgattdescriptor.enable_notification_value); mbluetoothgatt.writedescriptor(descriptor); } } public list<bluetoothgattservice> getsupportedgattservices() { if (mbluetoothgatt == null) return null; return mbluetoothgatt.getservices(); } } devicescanactivity.java:
public class devicescanactivity extends listactivity { ...... @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); getactionbar().settitle(r.string.title_devices); mhandler = new handler(); if (!getpackagemanager().hassystemfeature(packagemanager.feature_bluetooth_le)) { toast.maketext(this, r.string.ble_not_supported, toast.length_short).show(); finish(); } final bluetoothmanager bluetoothmanager = (bluetoothmanager) getsystemservice(context.bluetooth_service); mbluetoothadapter = bluetoothmanager.getadapter(); if (mbluetoothadapter == null) { toast.maketext(this, r.string.error_bluetooth_not_supported, toast.length_short).show(); finish(); return; } } @override public boolean oncreateoptionsmenu(menu menu) { getmenuinflater().inflate(r.menu.main, menu); if (!mscanning) { menu.finditem(r.id.menu_stop).setvisible(false); menu.finditem(r.id.menu_scan).setvisible(true); menu.finditem(r.id.menu_refresh).setactionview(null); } else { menu.finditem(r.id.menu_stop).setvisible(true); menu.finditem(r.id.menu_scan).setvisible(false); menu.finditem(r.id.menu_refresh).setactionview( r.layout.actionbar_indeterminate_progress); } return true; } @override public boolean onoptionsitemselected(menuitem item) { switch (item.getitemid()) { case r.id.menu_scan: mledevicelistadapter.clear(); scanledevice(true); break; case r.id.menu_stop: scanledevice(false); break; } return true; } @override protected void onresume() { super.onresume(); if (!mbluetoothadapter.isenabled()) { if (!mbluetoothadapter.isenabled()) { intent enablebtintent = new intent(bluetoothadapter.action_request_enable); startactivityforresult(enablebtintent, request_enable_bt); } } // initializes list view adapter. mledevicelistadapter = new ledevicelistadapter(); setlistadapter(mledevicelistadapter); scanledevice(true); } @override protected void onactivityresult(int requestcode, int resultcode, intent data) { if (requestcode == request_enable_bt && resultcode == activity.result_canceled) { finish(); return; } super.onactivityresult(requestcode, resultcode, data); } @override protected void onpause() { super.onpause(); scanledevice(false); mledevicelistadapter.clear(); } @override protected void onlistitemclick(listview l, view v, int position, long id) { .... startactivity(intent); } private void scanledevice(final boolean enable) { if (enable) { mhandler.postdelayed(new runnable() { @override public void run() { mscanning = false; mbluetoothadapter.stoplescan(mlescancallback); invalidateoptionsmenu(); } }, scan_period); mscanning = true; mbluetoothadapter.startlescan(mlescancallback); } else { mscanning = false; mbluetoothadapter.stoplescan(mlescancallback); } invalidateoptionsmenu(); } private class ledevicelistadapter extends baseadapter { private arraylist<bluetoothdevice> mledevices; private layoutinflater minflator; public ledevicelistadapter() { super(); mledevices = new arraylist<bluetoothdevice>(); minflator = devicescanactivity.this.getlayoutinflater(); } public void adddevice(bluetoothdevice device) { if(!mledevices.contains(device)) { mledevices.add(device); } } public bluetoothdevice getdevice(int position) { return mledevices.get(position); } public void clear() { mledevices.clear(); } @override public int getcount() { return mledevices.size(); } @override public object getitem(int i) { return mledevices.get(i); } @override public long getitemid(int i) { return i; } @override public view getview(int i, view view, viewgroup viewgroup) { viewholder viewholder; // general listview optimization code. if (view == null) { view = minflator.inflate(r.layout.listitem_device, null); viewholder = new viewholder(); viewholder.deviceaddress = (textview) view.findviewbyid(r.id.device_address); viewholder.devicename = (textview) view.findviewbyid(r.id.device_name); view.settag(viewholder); } else { viewholder = (viewholder) view.gettag(); } bluetoothdevice device = mledevices.get(i); final string devicename = device.getname(); if (devicename != null && devicename.length() > 0) viewholder.devicename.settext(devicename); else viewholder.devicename.settext(r.string.unknown_device); viewholder.deviceaddress.settext(device.getaddress()); return view; } } // device scan callback. private bluetoothadapter.lescancallback mlescancallback = new bluetoothadapter.lescancallback() { @override public void onlescan(final bluetoothdevice device, int rssi, byte[] scanrecord) { runonuithread(new runnable() { @override public void run() { mledevicelistadapter.adddevice(device); mledevicelistadapter.notifydatasetchanged(); } }); } }; ..... } devicecontrolactivity.java:
public class devicecontrolactivity extends activity { ........ private final serviceconnection mserviceconnection = new serviceconnection() { @override public void onserviceconnected(componentname componentname, ibinder service) { mbluetoothleservice = ((bluetoothleservice.localbinder) service).getservice(); if (!mbluetoothleservice.initialize()) { log.e(tag, "unable initialize bluetooth"); finish(); } mbluetoothleservice.connect(mdeviceaddress); } @override public void onservicedisconnected(componentname componentname) { mbluetoothleservice = null; } }; private final broadcastreceiver mgattupdatereceiver = new broadcastreceiver() { @override public void onreceive(context context, intent intent) { final string action = intent.getaction(); if (bluetoothleservice.action_gatt_connected.equals(action)) { mconnected = true; updateconnectionstate(r.string.connected); invalidateoptionsmenu(); } else if (bluetoothleservice.action_gatt_disconnected.equals(action)) { mconnected = false; updateconnectionstate(r.string.disconnected); invalidateoptionsmenu(); clearui(); } else if (bluetoothleservice.action_gatt_services_discovered.equals(action)) { // show supported services , characteristics on user interface. displaygattservices(mbluetoothleservice.getsupportedgattservices()); } else if (bluetoothleservice.action_data_available.equals(action)) { displaydata(intent.getstringextra(bluetoothleservice.extra_data)); } } }; private final expandablelistview.onchildclicklistener serviceslistclicklistner = new expandablelistview.onchildclicklistener() { @override public boolean onchildclick(expandablelistview parent, view v, int groupposition, int childposition, long id) { if (mgattcharacteristics != null) { final bluetoothgattcharacteristic characteristic = mgattcharacteristics.get(groupposition).get(childposition); final int charaprop = characteristic.getproperties(); if ((charaprop | bluetoothgattcharacteristic.property_read) > 0) { // if there active notification on characteristic, clear // first doesn't update data field on user interface. if (mnotifycharacteristic != null) { mbluetoothleservice.setcharacteristicnotification( mnotifycharacteristic, false); mnotifycharacteristic = null; } mbluetoothleservice.readcharacteristic(characteristic); } if ((charaprop | bluetoothgattcharacteristic.property_notify) > 0) { mnotifycharacteristic = characteristic; mbluetoothleservice.setcharacteristicnotification( characteristic, true); } return true; } return false; } }; private void clearui() { mgattserviceslist.setadapter((simpleexpandablelistadapter) null); mdatafield.settext(r.string.no_data); } @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.gatt_services_characteristics); final intent intent = getintent(); mdevicename = intent.getstringextra(extras_device_name); mdeviceaddress = intent.getstringextra(extras_device_address); ((textview) findviewbyid(r.id.device_address)).settext(mdeviceaddress); mgattserviceslist = (expandablelistview) findviewbyid(r.id.gatt_services_list); mgattserviceslist.setonchildclicklistener(serviceslistclicklistner); mconnectionstate = (textview) findviewbyid(r.id.connection_state); mdatafield = (textview) findviewbyid(r.id.data_value); getactionbar().settitle(mdevicename); getactionbar().setdisplayhomeasupenabled(true); intent gattserviceintent = new intent(this, bluetoothleservice.class); bindservice(gattserviceintent, mserviceconnection, bind_auto_create); } @override protected void onresume() { super.onresume(); registerreceiver(mgattupdatereceiver, makegattupdateintentfilter()); if (mbluetoothleservice != null) { final boolean result = mbluetoothleservice.connect(mdeviceaddress); log.d(tag, "connect request result=" + result); } } @override protected void onpause() { super.onpause(); unregisterreceiver(mgattupdatereceiver); } @override protected void ondestroy() { super.ondestroy(); unbindservice(mserviceconnection); mbluetoothleservice = null; } @override public boolean oncreateoptionsmenu(menu menu) { getmenuinflater().inflate(r.menu.gatt_services, menu); if (mconnected) { menu.finditem(r.id.menu_connect).setvisible(false); menu.finditem(r.id.menu_disconnect).setvisible(true); } else { menu.finditem(r.id.menu_connect).setvisible(true); menu.finditem(r.id.menu_disconnect).setvisible(false); } return true; } @override public boolean onoptionsitemselected(menuitem item) { switch(item.getitemid()) { case r.id.menu_connect: mbluetoothleservice.connect(mdeviceaddress); return true; case r.id.menu_disconnect: mbluetoothleservice.disconnect(); return true; case android.r.id.home: onbackpressed(); return true; } return super.onoptionsitemselected(item); } private void updateconnectionstate(final int resourceid) { runonuithread(new runnable() { @override public void run() { mconnectionstate.settext(resourceid); } }); } private void displaydata(string data) { if (data != null) { mdatafield.settext(data); } } private void displaygattservices(list<bluetoothgattservice> gattservices) { if (gattservices == null) return; string uuid = null; string unknownservicestring = getresources().getstring(r.string.unknown_service); string unknowncharastring = getresources().getstring(r.string.unknown_characteristic); arraylist<hashmap<string, string>> gattservicedata = new arraylist<hashmap<string, string>>(); arraylist<arraylist<hashmap<string, string>>> gattcharacteristicdata = new arraylist<arraylist<hashmap<string, string>>>(); mgattcharacteristics = new arraylist<arraylist<bluetoothgattcharacteristic>>(); // loops through available gatt services. (bluetoothgattservice gattservice : gattservices) { hashmap<string, string> currentservicedata = new hashmap<string, string>(); uuid = gattservice.getuuid().tostring(); currentservicedata.put( list_name, samplegattattributes.lookup(uuid, unknownservicestring)); currentservicedata.put(list_uuid, uuid); gattservicedata.add(currentservicedata); arraylist<hashmap<string, string>> gattcharacteristicgroupdata = new arraylist<hashmap<string, string>>(); list<bluetoothgattcharacteristic> gattcharacteristics = gattservice.getcharacteristics(); arraylist<bluetoothgattcharacteristic> charas = new arraylist<bluetoothgattcharacteristic>(); // loops through available characteristics. (bluetoothgattcharacteristic gattcharacteristic : gattcharacteristics) { charas.add(gattcharacteristic); hashmap<string, string> currentcharadata = new hashmap<string, string>(); uuid = gattcharacteristic.getuuid().tostring(); currentcharadata.put( list_name, samplegattattributes.lookup(uuid, unknowncharastring)); currentcharadata.put(list_uuid, uuid); gattcharacteristicgroupdata.add(currentcharadata); } mgattcharacteristics.add(charas); gattcharacteristicdata.add(gattcharacteristicgroupdata); } simpleexpandablelistadapter gattserviceadapter = new simpleexpandablelistadapter( this, gattservicedata, android.r.layout.simple_expandable_list_item_2, new string[] {list_name, list_uuid}, new int[] { android.r.id.text1, android.r.id.text2 }, gattcharacteristicdata, android.r.layout.simple_expandable_list_item_2, new string[] {list_name, list_uuid}, new int[] { android.r.id.text1, android.r.id.text2 } ); mgattserviceslist.setadapter(gattserviceadapter); } private static intentfilter makegattupdateintentfilter() { final intentfilter intentfilter = new intentfilter(); intentfilter.addaction(bluetoothleservice.action_gatt_connected); intentfilter.addaction(bluetoothleservice.action_gatt_disconnected); intentfilter.addaction(bluetoothleservice.action_gatt_services_discovered); intentfilter.addaction(bluetoothleservice.action_data_available); return intentfilter; } } i using google's official bluetoothlegatt example
i had issue , resolved adding uses-permission android:name="android.permission.access_coarse_location"
to manifest , decreasing target sdk version 21. happened permission infrastructure changed in new android 23. necessary grant permission while app running , not @ installation time. if target sdk 23 , want low energy scan, need grant above mention permission app before start calling scan(...) method.
Comments
Post a Comment