I'm trying to manage several Bluetooth events from my app so the user will not need to leave the app & try to search/pair Bluetooth devices from Android settings.
I'm able to enumerate previously paired devices, and start discovery, however I cant find nearby devices.
Background info:
Device = Samsung Galaxy S6
OS = Android 6.0.1 , Kernel 3.4.0-750027
Bluetooth devices are visible via Android's own built in discovery
Here is my relevant code:
package experiment.xyz.abc;
import android.app.ListActivity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
*
* This activity is responsible for bluetooth device discovery, pairing, and selection.
* 1) user can search for nearby devices
* 2) pair with device
* 3) unpair a device
* 4) select a bt device( upon successful selection the activity navigates away).
*/
public class BluetDeviceListActivity extends ListActivity
{
public static String BLUETOOTH_DEVICE_ADDRESS= "BLUETOOTH_DEVICE_ADDRESS";
List<BluetoothDevice> bluetList;
BluetoothDeviceListAdapter newBluetoothDeviceListAdapter = null;
private Set<BluetoothDevice> pairedDevices;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bluet_list_view);
//instantiate adapter
newBluetoothDeviceListAdapter = new BluetoothDeviceListAdapter(this);
//populate bluet list
populatePairedBluetoothDevices();
//set the ListActivity's adapter with our custom adapter
setListAdapter(newBluetoothDeviceListAdapter);
//on item click get the associated item based index & use Intent to send BluetoothDevice
getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
BluetoothDevice bluetoothDevice= newBluetoothDeviceListAdapter.getListOfBluetoothDevices().get(position);
if (bluetoothDevice!=null) {
Intent returnIntent = new Intent();
returnIntent.putExtra(BLUETOOTH_DEVICE_ADDRESS, bluetoothDevice.getAddress());
setResult(RESULT_OK, returnIntent);
}
finish();
if (mReceiver!=null)
{
try {
unregisterReceiver(mReceiver);
}
catch (IllegalArgumentException exc)
{
exc.printStackTrace();
}
}
}
});
//cancel activity dialog
Button cancelButton = (Button) findViewById(R.id.cancelBluetoothDialogButton);
cancelButton.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
if (mReceiver!=null)
{
try {
unregisterReceiver(mReceiver);
}
catch (IllegalArgumentException exc)
{
exc.printStackTrace();
}
}
}
});
//search for bluetooth devices
Button searchAndPairButton = (Button) findViewById(R.id.searchPairButton);
searchAndPairButton.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
//update textview
populateDiscoveredBluetoothDevices();
}
});
//pair or unpair selected device
Button pairOrUnpairButton = (Button) findViewById(R.id.pairUnpairDialogButton);
pairOrUnpairButton.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
//TODO:
}
});
}//end onCreate
//discover nearby devices & add to list
private void populateDiscoveredBluetoothDevices()
{
StreamApiUtility.getBluetoothAdapter();
//is bluet enabled
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
//if already discovering cancel
if(mBluetoothAdapter.isDiscovering()){
mBluetoothAdapter.cancelDiscovery();
}
//start a new discovery
mBluetoothAdapter.startDiscovery();
}//end there are paired devices
else
{
Log.i("EEGdataCapture", "No paired devices, select Search & Pair.");
TextView textView =(TextView) findViewById(R.id.textViewBluetoothListInstruction);
textView.setText("No paired devices, select Search & Pair.");
}
}
//query already paired & add to list
private void populatePairedBluetoothDevices()
{
StreamApiUtility.getBluetoothAdapter();
//is bluet enabled
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
//if already discovering cancel
if(mBluetoothAdapter.isDiscovering()){
mBluetoothAdapter.cancelDiscovery();
}
//start a new discovery
mBluetoothAdapter.startDiscovery();
//iterate paired/bonded devices and if there are any add them to the custom adapter
pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
BluetoothDevice bluetoothDevice;
Iterator<BluetoothDevice> it = pairedDevices.iterator();
while (it.hasNext()) {
bluetoothDevice = (BluetoothDevice) it.next();
//add to adapter
newBluetoothDeviceListAdapter.addDevice(bluetoothDevice);
newBluetoothDeviceListAdapter.notifyDataSetChanged();
Log.i("EEGdataCapture", "paired device, name: " + bluetoothDevice.getName() + ", address: " + bluetoothDevice.getAddress());
}
}//end there are paired devices
else
{
Log.i("EEGdataCapture", "No paired devices, select Search & Pair.");
TextView textView =(TextView) findViewById(R.id.textViewBluetoothListInstruction);
textView.setText("No paired devices, select Search & Pair.");
}
}
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice device;
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.i("EEGdataCapture", "BluetoothDevice.ACTION_FOUND");
Log.i("EEGdataCapture", device.getName() + "\n" + device.getAddress());
//update list
newBluetoothDeviceListAdapter.addDevice(device);
newBluetoothDeviceListAdapter.notifyDataSetChanged();
}
else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
Log.i("EEGdataCapture", "BluetoothDevice.ACTION_BOND_STATE_CHANGED");
final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
final int prevState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.ERROR);
if (state == BluetoothDevice.BOND_BONDED && prevState == BluetoothDevice.BOND_BONDING) {
Toast.makeText(MyApp.getAppContext(), "Paired", Toast.LENGTH_SHORT).show();
} else if (state == BluetoothDevice.BOND_NONE && prevState == BluetoothDevice.BOND_BONDED) {
Toast.makeText(MyApp.getAppContext(), "Unpaired", Toast.LENGTH_SHORT).show();
}
}
else if (BluetoothDevice.ACTION_UUID.equals(action)) {
Log.i("EEGdataCapture", "BluetoothDevice.ACTION_UUID");
}
else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
Log.i("EEGdataCapture", "BluetoothAdapter.ACTION_DISCOVERY_STARTED, Discovery Started...");
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
Log.i("EEGdataCapture", "BluetoothAdapter.ACTION_DISCOVERY_FINISHED, Discovery finished.");
}
else
{
Log.i("EEGdataCapture", "BluetoothAdapter, ACTIOM is not supported, action ="+action);
}
}};
private void pairDevice(BluetoothDevice device) {
try {
Method method = device.getClass().getMethod("createBond", (Class[]) null);
method.invoke(device, (Object[]) null);
} catch (Exception e) {
e.printStackTrace();
}
}
private void unpairDevice(BluetoothDevice device) {
try {
Method method = device.getClass().getMethod("removeBond", (Class[]) null);
method.invoke(device, (Object[]) null);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onPause() {
super.onPause();
if ( StreamApiUtility.getBluetoothAdapter()!=null) {
StreamApiUtility.getBluetoothAdapter().cancelDiscovery();
}
if (mReceiver!=null)
{
try {
unregisterReceiver(mReceiver);
}
catch (IllegalArgumentException exc)
{
exc.printStackTrace();
}
}
}
#Override
protected void onResume()
{
super.onResume();
//filter to capture bluet events
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothDevice.ACTION_UUID);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
//register listener for bluet events before starting discovery again
registerReceiver(mReceiver, filter);
}
#Override
protected void onDestroy() {
super.onDestroy();
if (mReceiver!=null)
{
try {
unregisterReceiver(mReceiver);
}
catch (IllegalArgumentException exc)
{
exc.printStackTrace();
}
}
}
}
updated Manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
The BroadcastReciever's BluetoothDevice.ACTION_FOUND is not being triggered/called although ACTION_DISCOVERY_STARTED OR ACTION_DISCOVERY_FINISHED are being called.
Help please???
Thanks
Your code seems ok. I guess you have the BLUETOOTH permission (otherwise you wouldn't receive the ACTION_DISCOVERY_STARTED) but do you also have the ACCESS_COARSE_LOCATION permission ?
You need it to receive ACTION_FOUND :
ACTION_FOUND
Broadcast Action: Remote device discovered.
Requires BLUETOOTH and ACCESS_COARSE_LOCATION to receive.
You need to perform a realtime-Permission check to ensure that Coarse Location is enabled before discovering any devices.
To do this, you should be targeting/minimum SDK 23+ in your build.gradle file.
if (mActivityContext.checkSelfPermission("android.permission.ACCESS_COARSE_LOCATION") == PackageManager.PERMISSION_GRANTED) {
final BluetoothManager bluetoothManager =
(BluetoothManager) mActivityContext.getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetoothManager != null) mBleAdapter = bluetoothManager.getAdapter();
Register Intent Filters here
mBleAdapter.startDiscovery();
} else {
mInterface.requestPermission(Manifest.permission.ACCESS_COARSE_LOCATION, mCoarsePermissionTag);
}
mInterface is my interface back to my MainActivity
Related
I've seen plenty of questions about how to connect to multiple devices purposely. But in my situation, I am only trying to connect to one hardware device.
I have two hardware devices that are supposed to do the same thing. When they connect to my app via BLE, then they have an LED that turns a solid color. This all works fine and dandy when I only have one device turned on. However, when I turn two of the devices on and then try to connect to just one. Both of the devices' LED's turn solid. Although I don't seem to be getting any incoming data from the one that I didn't intend to connect to.
I don't think it's the device's fault. Because I don't have this issue on iOS. I think the phone might be remembering previously connected devices somewhere maybe?
I'm sorry, this is a lot of code. But I feel like it's important to have this whole class. Any help is much appreciated.
package com.roberts.croberts.orange;
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.bluetooth.le.BluetoothLeScanner;
import java.util.ArrayList;
import java.util.List;
#TargetApi(21)
public class BluetoothRegulator {
private static BluetoothRegulator instance = null;
private Context context;
private BluetoothLeScanner mLEScanner;
private BluetoothDevice orangeDevice;
//scanner stuff
private Handler mHandler;
// Stops scanning after 3 seconds.
private static final long SCAN_PERIOD = 3000;
//connected stuff
private android.bluetooth.BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mBluetoothGatt;
public ArrayList<BluetoothDevice> devices = new ArrayList<>();
private Handler foundHandler = new Handler();
private Handler servicesHandler = new Handler();
private ScanCallback mScanCallback;
public static BluetoothRegulator sharedInstance(){
if(instance == null) {
instance = new BluetoothRegulator();
Log.i("chase", "created new instance");
}
return instance;
}
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBluetoothGatt.discoverServices();
Log.i(TAG, "BR: onconnectionsStateChanged Connected to GATT server.");
// Attempts to discover services after successful connection.
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// Loops through available GATT Serviceokay so ees.
for (BluetoothGattService gattService : mBluetoothGatt.getServices()) {
for (BluetoothGattCharacteristic gattCharacteristic : gattService.getCharacteristics()) {
mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
Log.i(TAG, mBluetoothGatt == null ? "mbluetooth is null" : "should be subscribed");
}
}
Log.i("chase", "did connect and discover devices");
} else {
Log.w(TAG, "Not Success onServicesDiscovered received: " + status);
connect(orangeDevice);
}
}
private Object getFieldFromObject(Object obj, String name){
try {
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
}catch(Exception e){
Log.i("chase", "e: "+e);
return null;
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
Log.i("BR: chase", "received data!");
}
};
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
public boolean initialize(android.bluetooth.BluetoothManager btmanager, Context ctx) {
mBluetoothManager = btmanager;
context = ctx;
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
if (Build.VERSION.SDK_INT >= 21) {
mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
setUpCallBack();
}
return true;
}
public void scan() { //we call scan when they hit the connect button...
// Stops scanning after a pre-defined scan period.
Log.i("chase", "start scanning");
devices = new ArrayList<>();
if (mHandler == null) mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}, SCAN_PERIOD);
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mLEScanner.startScan(mScanCallback);
}
}
private void foundDevice(BluetoothDevice device){
final String deviceName = device.getName();
if (deviceName != null && deviceName.length() > 5 && (deviceName.substring(0, 6).equals("orange") || deviceName.substring(0, 6).equals("smartb"))) {
for (BluetoothDevice d : devices){
if (d.getAddress().equals(device.getAddress())){
return;
}
}
mHandler.removeCallbacksAndMessages(null);
devices.add(device);
if (devices.size() == 1) { //wait one second and then assume there aren't any more devices named "orange"
foundHandler.postDelayed(new Runnable() {
public void run() {
doneSearching();
}
}, 1000);
}
}
}
private void doneSearching(){
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
if (devices.size() == 1){
BluetoothDevice device = devices.get(0);
connect(device);
}else{
//normally this displays a list and the user can choose which device. But this works just as well for now.
BluetoothDevice device = devices.get(0);
connect(device);
}
}
//connect method
public boolean connect(BluetoothDevice btdevice) {
orangeDevice = btdevice;
if (mBluetoothAdapter == null || btdevice == null || btdevice.getAddress() == null) {
return false;
}
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
devices = new ArrayList<>();
mBluetoothGatt = orangeDevice.connectGatt(context, true, mGattCallback);
return true;
}
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) return;
mBluetoothGatt.disconnect();
mBluetoothGatt = null;
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
foundDevice(device);
}
};
public void setUpCallBack(){
mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
foundDevice(device);
}
#Override
public void onScanFailed(int errorCode) {
Log.e("Chase", "Scan Failed Error Code: " + errorCode);
}
};
}
}
Update
I was playing around with a galaxy tablet and wasn't able to recreate the issue. So I think it's device dependent. The problem occurs on the Galaxy S3, and I am trying to round up some other devices to test with.
Also, I was able to get my hands on some new devices and it seems that if the device has never been connected before to the phone (virgin device) then that device doesn't get mixed up and think it's connected when it's not. So we will see it when we search but it never thinks I am connecting to it, until I actually do connect to it. After that, then half the time it thinks I am trying to talk to it when I am not. I hope that makes sense. Which backs up the theory that the phone is somehow caching old devices. I tried uninstalling the app and reinstalling it to see if it would have the same effect as using a virgin device, but it seems the app has nothing to do with it. The device will still connect (when it's not supposed to) after it has been introduced to the phone, even if I did a fresh install of the app.
I would check the BLE devices themselves. Is there a chance that they might have the same System ID ? I believe it's the first characteristic in 0x180A. If so - it will be difficult for the host to distinguish them and such a double connection might happen.
-Lets say you have 2 devices. So foundDevice() gets called. Now devices arraylist contains 1 device.
-After that you are using handler which calls doneSearching() & checks
if device.size()==1
It returns true and you call connect()
-Inside connect you are again creating an arraylist i.e
devices = new ArrayList<>();
So what happens now is your devices ArrayList<>() contains 0 elements.
-So now when 2nd device is found again the above steps are repeated because whenever connect method is getting called, the size of list is getting refreshed to 0
So just remove the line
devices = new ArrayList<>();
inside connect() method
I am making some experiments with Android Open Accessory Protocol (AOA) using various phones/tablets and Arduino DUE.
I need some help to try to find the cause of a different behaviour of a simple app based on AOA that reads data from an analog input pin and that changes the status of a digital output pin of the Arduino DUE.
All phones on which I am trying the app are not rooted and I have verified that all of them have the files
/system/framework/com.android.future.usb.accessory.jar
/system/etc/permissions/android.hardware.usb.accessory.xml
that, as long as I know, are the only two requested to give support to AOA.
The named app works well on a Samsung Galaxy S2 (Android version 4.1.2, kernel v3.0.31-1211311) and on a Galaxy Pocket Neo (Android version 4.1.2, kernel v3.0.15-1456085), but works only "partially" on a Samsung Galaxy Note 3 (Android version 4.3, kernel v3.4.0-2019540).
In more detail, when I connect the accessory to all of the specified phones (also the Galaxy Note 3), it is correctly recognized and the app associated to the Arduino sketch controls correctly (an all phones) the status of the digital output pin, but the Galaxy Note seems to don't be able to receive from Arduino and to display the message containing the result of the analog-to-digital conversion (two bytes).
The app is one of the tutorial projects of the UDOO development platform and the original post is here: http://www.udoo.org/ProjectsAndTutorials/android-and-arduino-on-udoo-bidirectional-communication/?portfolioID=1394
Here is the code of MainActivity.java:
package org.udoo.androidadkdemobidirect;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.udoo.androidadkdemobidirect.R;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
public class MainActivity extends Activity implements Runnable{
private static final String TAG = "UDOO_AndroidADKFULL";
private static final String ACTION_USB_PERMISSION = "org.udoo.androidadkdemobidirect.action.USB_PERMISSION";
private UsbManager mUsbManager;
private PendingIntent mPermissionIntent;
private boolean mPermissionRequestPending;
private Message m;
UsbAccessory mAccessory;
ParcelFileDescriptor mFileDescriptor;
FileInputStream mInputStream;
FileOutputStream mOutputStream;
private static ToggleButton btn_LED = null;
private static TextView tv_adResult = null;
private boolean running = false;
// Receive the USB attached intent
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (intent.getBooleanExtra(
UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
openAccessory(accessory);
} else {
Log.d(TAG, "permission denied for accessory "+ accessory);
}
mPermissionRequestPending = false;
}
} else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (accessory != null && accessory.equals(mAccessory)) {
closeAccessory();
}
}
}
};
#SuppressWarnings("deprecation")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
registerReceiver(mUsbReceiver, filter);
if (getLastNonConfigurationInstance() != null) {
mAccessory = (UsbAccessory) getLastNonConfigurationInstance();
openAccessory(mAccessory);
}
setContentView(R.layout.activity_main);
btn_LED = (ToggleButton) findViewById(R.id.toggleButtonLED);
tv_adResult = (TextView) findViewById(R.id.adResult);
}
#SuppressWarnings("deprecation")
#Override
public Object onRetainNonConfigurationInstance() {
if (mAccessory != null) {
return mAccessory;
} else {
return super.onRetainNonConfigurationInstance();
}
}
#Override
public void onResume() {
super.onResume();
if (mInputStream != null && mOutputStream != null) {
running = true;
return;
}
//open the accessory from the accessory list
UsbAccessory[] accessories = mUsbManager.getAccessoryList();
UsbAccessory accessory = (accessories == null ? null : accessories[0]);
if (accessory != null) {
if (mUsbManager.hasPermission(accessory)) {
openAccessory(accessory);
} else {
synchronized (mUsbReceiver) {
if (!mPermissionRequestPending) {
mUsbManager.requestPermission(accessory,mPermissionIntent);
mPermissionRequestPending = true;
}
}
}
} else {
Log.d(TAG, "mAccessory is null");
}
}
#Override
public void onPause() {
running = false;
super.onPause();
}
#Override
public void onDestroy() {
running = false;
closeAccessory();
unregisterReceiver(mUsbReceiver);
super.onDestroy();
}
// open the accessory and open the input and output stream from the descriptor
// start also the thread that reads from Arduino
private void openAccessory(UsbAccessory accessory) {
mFileDescriptor = mUsbManager.openAccessory(accessory);
if (mFileDescriptor != null) {
mAccessory = accessory;
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
Thread thread = new Thread(this, "UDOO_ADK_readfrom");
running = true;
thread.start();
Toast.makeText(getApplicationContext(), "Accessory connected", Toast.LENGTH_SHORT).show();
Log.i(TAG, "openaccessory");
}
else {
Toast.makeText(getApplicationContext(), "Accessory not connected", Toast.LENGTH_SHORT).show();
}
}
// close the accessory
private void closeAccessory() {
Log.i(TAG, "closeaccessory");
try {
if (mFileDescriptor != null) {
mFileDescriptor.close();
}
} catch (IOException e) {
} finally {
mFileDescriptor = null;
mAccessory = null;
running = false;
}
}
// ToggleButton method - send message to Arduino
public void writeToAccessory(View v){
if (mAccessory != null) {
byte[] message = new byte[1];
message[0] = (byte) (btn_LED.isChecked()?1:0);
if (mOutputStream != null) {
try {
mOutputStream.write(message);
} catch (IOException e) {
Log.e(TAG, "write failed", e);
}
}
}
else
Toast.makeText(getApplicationContext(), "Accessory not connected", Toast.LENGTH_SHORT).show();
}
// Thread to read data from Arduino
public void run() {
int ret = 0;
byte[] buffer = new byte[4];
while (running) {
try {
ret = mInputStream.read(buffer);
} catch (IOException e) {
break;
}
m = Message.obtain(mHandler);
if (ret != 0) {
m.arg1 = (int) ((buffer[0] & 0xff) << 8) + (buffer[1] & 0xff);
ret = 0;
}
mHandler.sendMessage(m);
}
}
static Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
final int temp = msg.arg1;
tv_adResult.setText(String.format("%4d (= %.2f V)", temp, 3.3/1024*temp));
}
};
}
I have also verified that this strange behaviour persists also for other apps based on the AOA Protocol, that is: the Galaxy Note 3 sends correctly the output messages to the accessory but doesn't read the input messages from it.
I am unable to find where the problem is and I would ask the StackOverflow Community to give me some hint.
Any help will be appreciated.
I am not sure if this helps, but you could try to disable USB Debugging from the Developer Options. Some phones have issue with the debugging mode on.
There are two different instances of my program not being about to connect to a BluetoothServerSocket.
One of the instances has only 1 UUID generated randomly before it initiates scan mode with SCAN_MODE_CONNECTABLE_DISCOVERABLE and before using the same generated UUID to create a BluetoothServerSocket for listening. The other intance generates a random UUID just before a BluetoothDevice tries to connect with the UUID just generated.
Each of the instances cannot complete the Bluetooth connection. Throughout the entire program, I put many Logs just to try and see why it wouldn't be able to connect.
Below is the code for the first instance. (Generate 1 random UUID at the launch of the app.) If anyone likes to download my Eclipse project just to take a look, here's the link of the project from MediaFire. As for the second instance, uncommenting the C-style comments in the code below will reveal it.
I expected the results would be to have a successful connection between two devices. The successful connection connects a device to a listening socket, by using a generated UUID. The observed results show it is unlikely.
As far as I know, the only way to obtain a UUID is to obtain it from UUID.randomUUID(). If there are other ways, please post a comment below, and I'll check it. But for now, it's not the answer I wanted.
Thanks in advance.
package o.p;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
/**
* The purpose of this app is to create a server-only Bluetooth connection that
* only accepts incoming Bluetooth connections. It is used only for testing
* one device that needs Bluetooth tweaking in order to consistently work
* correctly on the other device. In short, 2 devices are required.
* */
public class Main extends Activity implements View.OnClickListener {
//Button
private Button acceptButton;
private Button scanButton;
//Bluetooth stuffs.
private BluetoothAdapter btAdapter;
private BluetoothServerSocket serverSocket;
private BluetoothSocket socket;
private BluetoothDevice targetDevice;
private final UUID uuid = UUID.randomUUID();
/*private UUID randomUUID;*/
//Accepting thread.
private class Accept implements Runnable {
private BluetoothServerSocket socket;
private BluetoothSocket result = null;
public Accept(BluetoothServerSocket s) {
socket = s;
result = null;
}
#Override
public void run() {
try {
Log.d("DEBUG", "Accepting.");
result = socket.accept();
Log.d("DEBUG", "Closing server socket.");
socket.close();
}
catch (IOException e) {
Log.d("DEBUG - onClick(), case Accept", "Unable to accept incoming connection.");
}
}
public BluetoothSocket getSocket() {
while (result == null);
return result;
}
}
//Connecting thread.
private class Connecting implements Runnable {
private BluetoothDevice device;
public Connecting(BluetoothDevice d) {
device = d;
}
#Override
public void run() {
try {
/*Log.d("DEBUG", "Generating a new random UUID.");
randomUUID = UUID.randomUUID();*/
Log.d("DEBUG", "Obtaining a socket.");
BluetoothSocket s = device.createRfcommSocketToServiceRecord(uuid);
Log.d("DEBUG", "Cancelling discovery, if it's still discovering.");
if (btAdapter.isDiscovering())
btAdapter.cancelDiscovery();
Log.d("DEBUG", "Connecting to listening socket with UUID: " + uuid.toString());
s.connect();
}
catch (IOException e) {
Log.d("DEBUG - Connecting.run()", "Unable to connect to the listening socket.");
}
}
}
//Thread executor
private ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
//BroadcastReceiver for accepting Bluetooth
private BroadcastReceiver receiver;
#Override
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.main);
init();
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_accept:
Log.d("DEBUG", "Pressing the Accept button.");
Accept acceptThread = new Accept(serverSocket);
Connecting connectThread = new Connecting(targetDevice);
if (serverSocket != null) {
executor.execute(acceptThread);
executor.execute(connectThread);
socket = acceptThread.getSocket();
}
else {
Log.d("DEBUG", "Server socket isn't ready.");
Toast.makeText(this, "Server socket isn't ready.", Toast.LENGTH_LONG).show();
}
break;
case R.id.button_scan:
if (btAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Log.d("DEBUG", "Initiating discovery scan mode.");
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
this.startActivity(discoverableIntent);
Toast.makeText(this, "Being discovered...", Toast.LENGTH_LONG).show();
}
if (btAdapter.isDiscovering()) {
Toast.makeText(this, "Re-scanning...", Toast.LENGTH_SHORT).show();
Log.d("DEBUG", "Re-scanning.");
btAdapter.cancelDiscovery();
}
Log.d("DEBUG", "Scanning.");
Toast.makeText(this, "Scanning...", Toast.LENGTH_LONG).show();
btAdapter.startDiscovery();
break;
}
}
private void init() {
Log.d("DEBUG", "Initializing.");
Log.d("DEBUG", "Button initializing.");
acceptButton = (Button) findViewById(R.id.button_accept);
acceptButton.setOnClickListener(this);
scanButton = (Button) findViewById(R.id.button_scan);
scanButton.setOnClickListener(this);
Log.d("DEBUG", "Registering BroadcastReceiver.");
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
Log.d("DEBUG", "Device has been found.");
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d("DEBUG", "Obtained a device from Intent.");
if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
Log.d("DEBUG", "Removing paired device.");
try {
Method m = device.getClass().getMethod("removeBond", (Class[]) null);
m.invoke(device, (Object[]) null);
Log.d("DEBUG", "Removed " + device);
}
catch (NoSuchMethodException e) {
Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
}
catch (IllegalArgumentException e) {
Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
}
catch (IllegalAccessException e) {
Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
}
catch (InvocationTargetException e) {
Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
}
}
else {
Log.d("DEBUG", "Obtaining remote device's address.");
btAdapter.getRemoteDevice(device.getAddress());
try {
serverSocket = btAdapter.listenUsingRfcommWithServiceRecord(device.getName(), uuid);
Log.d("DEBUG", "Listening to " + device.getName() + "...");
}
catch (IOException e) {
Log.d("DEBUG - onReceive()", "Unable to create a server socket after receiving a broadcast.", e);
serverSocket = null;
Log.d("DEBUG", "Server socket is set to null.");
}
}
targetDevice = device;
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
Log.d("DEBUG", "Scanning finished.");
}
}
};
Log.d("DEBUG", "Creating Bluetooth Adapter.");
btAdapter = BluetoothAdapter.getDefaultAdapter();
try {
Log.d("DEBUG", "Creating a server socket for listening using UUID: " + uuid.toString());
serverSocket = btAdapter.listenUsingRfcommWithServiceRecord("server", uuid);
}
catch (IOException e) {
Log.d("DEBUG - init()", "Error in creating a server socket from uuid.");
}
}
#Override
public void onResume() {
super.onResume();
//TODO: Not done with the receivers.
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
}
#Override
public void onPause() {
//TODO: Complete this one. Same for onResume().
super.onPause();
unregisterReceiver(receiver);
}
}
To be able to connect the UUIDs should match.
On the Server side what you are doing is correct i.e generating a ramdom UUID and listening on it,
But the client needs to connect using the same UUID that the server is listening on.
The way to get it will be from your client use the fetchUuidsWithSdp() on the Server BluetoothDevice object and use the obtained UUID to connect to the server.
I am using DeviceListActivity for discovering Bluetooth devices. This is the activity that is used on Android Bluetooth Chat program sample.
I run the program on a virtual machine.
Problem: When I start scanning/discovering Bluetooth devices:
it lists duplicate devices name:
I have one device that is discoverable but the program lists it more than once.
How can I prevent to list duplicate devices name?
The activity code:
package com.example.android.BluetoothChat;
import java.util.Set;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
/**
* This Activity appears as a dialog. It lists any paired devices and
* devices detected in the area after discovery. When a device is chosen
* by the user, the MAC address of the device is sent back to the parent
* Activity in the result Intent.
*/
public class DeviceListActivity extends Activity {
// Debugging
private static final String TAG = "DeviceListActivity";
private static final boolean D = true;
// Return Intent extra
public static String EXTRA_DEVICE_ADDRESS = "device_address";
// Member fields
private BluetoothAdapter mBtAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private ArrayAdapter<String> mNewDevicesArrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Setup the window
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.device_list);
// Set result CANCELED incase the user backs out
setResult(Activity.RESULT_CANCELED);
// Initialize the button to perform device discovery
Button scanButton = (Button) findViewById(R.id.button_scan);
scanButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
doDiscovery();
v.setVisibility(View.GONE);
}
});
// Initialize array adapters. One for already paired devices and
// one for newly discovered devices
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
// Find and set up the ListView for paired devices
ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(mDeviceClickListener);
// Find and set up the ListView for newly discovered devices
ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
newDevicesListView.setOnItemClickListener(mDeviceClickListener);
// Register for broadcasts when a device is discovered
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
// Register for broadcasts when discovery has finished
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
// Get the local Bluetooth adapter
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
// Get a set of currently paired devices
Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
// If there are paired devices, add each one to the ArrayAdapter
if (pairedDevices.size() > 0) {
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else {
String noDevices = getResources().getText(R.string.none_paired).toString();
mPairedDevicesArrayAdapter.add(noDevices);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
// Make sure we're not doing discovery anymore
if (mBtAdapter != null) {
mBtAdapter.cancelDiscovery();
}
// Unregister broadcast listeners
this.unregisterReceiver(mReceiver);
}
/**
* Start device discover with the BluetoothAdapter
*/
private void doDiscovery() {
if (D) Log.d(TAG, "doDiscovery()");
// Indicate scanning in the title
setProgressBarIndeterminateVisibility(true);
setTitle(R.string.scanning);
// Turn on sub-title for new devices
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
// If we're already discovering, stop it
if (mBtAdapter.isDiscovering()) {
mBtAdapter.cancelDiscovery();
}
// Request discover from BluetoothAdapter
mBtAdapter.startDiscovery();
}
// The on-click listener for all devices in the ListViews
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
// Cancel discovery because it's costly and we're about to connect
mBtAdapter.cancelDiscovery();
// Get the device MAC address, which is the last 17 chars in the View
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
// Create the result Intent and include the MAC address
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
// Set result and finish this Activity
setResult(Activity.RESULT_OK, intent);
finish();
}
};
// The BroadcastReceiver that listens for discovered devices and
// changes the title when discovery is finished
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// If it's already paired, skip it, because it's been listed already
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
// When discovery is finished, change the Activity title
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setProgressBarIndeterminateVisibility(false);
setTitle(R.string.select_device);
if (mNewDevicesArrayAdapter.getCount() == 0) {
String noDevices = getResources().getText(R.string.none_found).toString();
mNewDevicesArrayAdapter.add(noDevices);
}
}
}
};
}
Edit:
This problem is disappeared on my real device(smart phone). I don't know why an emulator has such problem!
Simple. To filter, use a Set.
Example
HashSet
Add bluetooth address on HashSet and verify with method contains().
if contains() returns false, then add the bluetooth data to the list
if contains() returns true, then DON'T add the bluetooth data to the list
Write this inside you ACTION_FOUND.
if (mNewDevicesArrayAdapter.size() < 1) {
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
mNewDevicesArrayAdapter.notifyDataSetChanged();
}
else {
boolean flag = true; // flag to indicate that particular device is already in the arlist or not
for(int i = 0; i<mNewDevicesArrayAdapter.size();i++)
{
if(device.getAddress().equals(mNewDevicesArrayAdapter.get(i).getAddress()))
{
flag = false;
}
}
if(flag == true)
{
mNewDevicesArrayAdapter.add(device.getName()+"\n"+device.getAddress());
mNewDevicesArrayAdapter.notifyDataSetChanged();
}
}
This one worked for me
public class MainActivity extends ActionBarActivity {
private ListView listView;
private ArrayList<String> mDeviceList = new ArrayList<String>();
private BluetoothAdapter mBluetoothAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.startDiscovery();
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
}
#Override
protected void onDestroy() {
unregisterReceiver(mReceiver);
super.onDestroy();
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
mDeviceList.add(device.getName() + "\n" + device.getAddress());
Log.i("BT", device.getName() + "\n" + device.getAddress());
listView.setAdapter(new ArrayAdapter<String>(context,
android.R.layout.simple_list_item_1, mDeviceList));
}
}
};
In onReceive of BluetoothDevice.ACTION_FOUND, before adding a BlueTooth device to the Arraylist check if the Arraylist already contains that device using the method contains() of the ArrayList.
Add the device to the list only if contains() returns false.
Code is as below:
List<BluetoothDevice> availableDevices = new ArrayList<>();
class BluetoothReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null) {
switch (action) {
case BluetoothDevice.ACTION_FOUND: {
// Discovery has found a device. Get the BluetoothDevice
// object and its info from the Intent.
BluetoothDevice bluetoothDevice =
intent.getParcelableExtra(BluetoothDevice
.EXTRA_DEVICE);
//Add the device to the list only if contains() returns false.
if (!availableDevices.contains(bluetoothDevice)) {
availableDevices.add(bluetoothDevice);
}
displayAvailableDevices();
break;
}
It worked for me
#Override
public void onDeviceDiscovered(BluetoothDevice device) {
listener.endLoading(true);
devices.contains(device);
//======================To add only unique device not repeating same device in listView========================
if( devices.contains(device)){
}else {
devices.add(device);
}
//======================End of add only unique device not repeating same device in listView====================
notifyDataSetChanged();
}
I am trying to connect 2 Android devices through Wi-fi Direct.
In my application I am hard coding the MAC address of the other device and calling the method connect. I am assuming that Wi-Fi Direct is on in both the devices. Here is the code I am using:
package com.abc;
import android.app.Activity;
import android.content.Context;
import android.content.IntentFilter;
import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.os.Bundle;
import android.widget.Toast;
public class WiFiDirectActivity extends Activity {
/** Called when the activity is first created. */
protected WifiP2pManager manager;
protected Channel channel;
public WifiP2pConfig config ;
protected final IntentFilter intentFilter = new IntentFilter();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intentFilter.addAction (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, this.getMainLooper(), null);
config = new WifiP2pConfig();
config.deviceAddress = "78:d6:f0:ab:d9:da";
config.groupOwnerIntent = 0;
config.wps.setup = WpsInfo.PBC;
manager.connect(channel, config, new WifiP2pManager.ActionListener(){
#Override
public void onSuccess() {
Toast.makeText(getApplicationContext(), "success", Toast.LENGTH_LONG);
}
#Override
public void onFailure(int reason) {
Toast.makeText(getApplicationContext(), "Failed", Toast.LENGTH_LONG);
}
});
}
}
but it is not connecting. What is wrong with my implementation?
I have a similar code working, the main differences are:
I get the device address calling before to discovery peers (If you do that then you have to add WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION to intent filter group)
I don't set the config.groupOwnerIntent
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = this.address;
config.wps.setup = WpsInfo.PBC;
register a BroadcastReceiver in onResume() and override it. remember to unregister it in onPause()
private class WiFiDirectBroadcastReceiver extends android.content.BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
//TODO
}
}
}
then try to call discoverPeers() first
mWifiP2pManager.discoverPeers(Channel mChannel, ActionListener mActionListener);
if discoverPeers() does find peers, action WIFI_P2P_PEERS_CHANGED_ACTION will be triggered.
we can call requestPeers() in WIFI_P2P_PEERS_CHANGED_ACTION in the BroadcastReceiver
mWifiP2pManager.requestPeers(Channel mChannel, WifiP2pManager.PeerListListener);
so our BroadcastReceiver now looks like this
private class WiFiDirectBroadcastReceiver extends android.content.BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
mWifiP2pManager.requestPeers(mChannel , pl);
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
//TODO
}
}
}
to implement WifiP2pManager.PeerListListener, you need to override onPeersAvailable(WifiP2pDeviceList peers)
in onPeersAvailable(), the parameter wifiP2pDeviceList means the peers you discovered
we need a UI object to let us choose which device to connect, so I use spinner here.
also you can use listView or something else.
private List<WifiP2pDevice> mPeers = new ArrayList<WifiP2pDevice>();
spinnerAdapter = new WiFiPeerListAdapter(this, R.layout.row_devices, mPeers);
...
#Override
public void onPeersAvailable(WifiP2pDeviceList wifiP2pDeviceList) {
mPeers.clear();
mPeers.addAll(wifiP2pDeviceList.getDeviceList());
spinnerAdapter.notifyDataSetChanged();
}
finally we can connect to a device
WifiP2pDevice device = spinnerAdapter.getItem((int) mSpinner.getSelectedItemId());
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
config.wps.setup = WpsInfo.PBC;
mWifiP2pManager.connect(mChannel, config, mActionListener);
after two device connected, BroadcastReceiver action WIFI_P2P_CONNECTION_CHANGED_ACTION will be triggered. so we can do something here.
our BroadcastReceiver now looks like
private class WiFiDirectBroadcastReceiver extends android.content.BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
//TODO
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
mWifiP2pManager.requestPeers(mChannel , pl);
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo != null) {
Log.d(TAG,networkInfo.toString());
if (networkInfo.isConnected()) {
mWifiP2pManager.requestConnectionInfo(mChannel, WifiP2pManager.ConnectionInfoListener);
}
}
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
//TODO
}
}
}
btw, the log in action WIFI_P2P_CONNECTION_CHANGED_ACTION will get something like this
NetworkInfo: type: WIFI_P2P[], state: UNKNOWN/IDLE, reason: (unspecified), extra: (none), roaming: false, failover: false, isAvailable: true, simId: 0
now we need to implement WifiP2pManager.ConnectionInfoListener and override its abstract method onConnectionInfoAvailable(WifiP2pInfo info) for requestConnectionInfo()
private WifiP2pInfo p2pInfo;
#Override
public void onConnectionInfoAvailable(final WifiP2pInfo info) {
p2pInfo = info;
mWifiP2pManager.requestGroupInfo(mChannel, WifiP2pManager.GroupInfoListener);
}
again we need to implement WifiP2pManager.GroupInfoListener and override onGroupInfoAvailable(WifiP2pGroup group)
#Override
public void onGroupInfoAvailable(WifiP2pGroup wifiP2pGroup) {
String log;
if(wifiP2pGroup.isGroupOwner()) {
log = "I am GO";
}else{
log = "I am not GO";
}
Log.d(TAG, log);
}
now we almost got every info about these two devices
enjoy it