I have an app that runs on 2 phones and allows the user to connect from one to the other using WifiP2p (WiFi Direct). On most phones, it works. Both phones go into peer discovery, they discover each other, one initiates a connection, and the other accepts. But when I try to connect to a Sony LT25i running Android 4.1.2, the pairing fails.
The code for initiating the connection is like this:
WifiP2pConfig wifiP2pConfig = new WifiP2pConfig();
wifiP2pConfig.deviceAddress = device.deviceAddress;
// Try to make a device that supports WifiDirect the group owner,
// so that a legacy device can connect to it as an access point.
wifiP2pConfig.groupOwnerIntent = 10;
// Wifi Protected Setup: Push Button Configuration. The other main option is PIN configuration.
wifiP2pConfig.wps.setup = WpsInfo.PBC;
mWifiP2pManager.connect(mChannel, wifiP2pConfig, new WifiP2pManager.ActionListener() {...
Unexpected group creation, remove network
When the problem occurs, when the initiating device runs the above code to attempt to connect, the Sony shows this interesting tidbit in Logcat:
02-02 05:22:55.494 669-781/? E/WifiP2pService: Unexpected group creation,
remove network: DIRECT-aq-LG Phoenix 2
isGO: false
GO: Device:
deviceAddress: de:0b:34:f0:11:78
primary type: null
secondary type: null
wps: 0
grpcapab: 0
devcapab: 0
status: 4
interface: p2p0
where "LG Phoenix 2" is the name of the phone initiating the pairing.
For some reason, WifiP2pService doesn't like the fact that a group is being created, and removes it. Why?
I looked up the error message "WifiP2pService: Unexpected group creation, remove"
and found this code in WifiP2pService.DefaultState.processMessage():
/* unexpected group created, remove */
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
mGroup = (WifiP2pGroup) message.obj;
loge("Unexpected group creation, remove " + mGroup);
mWifiNative.p2pGroupRemove(mGroup.getInterface());
break;
So apparently this happens because the WifiP2pService is in DefaultState? By contrast, WifiP2pService.P2pEnabledState.processMessage() doesn't have a case for P2P_GROUP_STARTED_EVENT. So maybe if the WifiP2pService were in the P2pEnabledState on the phone, I wouldn't be having this group removal problem.
But according to the logs, WifiP2p is enabled: I'm catching the WIFI_P2P_STATE_CHANGED_ACTION broadcast and logging the value of EXTRA_WIFI_STATE. So why is WifiP2pService apparently in DefaultState?
By the way, pairing used to work on the Sony, but yesterday I connected the device to my home Wifi router and it doesn't seem to have worked ever since, even though I disconnected it from the router.
I've tried turning off Wifi, turning it back on, removing ("forgetting") my home Wifi router, and rebooting the phones, and connecting from other phones besides the LG. Nothing fixes the problem.
This code that you have is very incomplete and needs to be completed. Note the sample of the code for you.
import android.app.Activity;
import android.app.Fragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
import android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener;
import android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.example.android.wifidirect.discovery.WiFiChatFragment.MessageTarget;
import com.example.android.wifidirect.discovery.WiFiDirectServicesList.DeviceClickListener;
import com.example.android.wifidirect.discovery.WiFiDirectServicesList.WiFiDevicesAdapter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class WiFiServiceDiscoveryActivity extends Activity implements
DeviceClickListener, Handler.Callback, MessageTarget,
ConnectionInfoListener {
public static final String TAG = "wifidirectdemo";
// TXT RECORD properties
public static final String TXTRECORD_PROP_AVAILABLE = "available";
public static final String SERVICE_INSTANCE = "_wifidemotest";
public static final String SERVICE_REG_TYPE = "_presence._tcp";
public static final int MESSAGE_READ = 0x400 + 1;
public static final int MY_HANDLE = 0x400 + 2;
private WifiP2pManager manager;
static final int SERVER_PORT = 4545;
private final IntentFilter intentFilter = new IntentFilter();
private Channel channel;
private BroadcastReceiver receiver = null;
private WifiP2pDnsSdServiceRequest serviceRequest;
private Handler handler = new Handler(this);
private WiFiChatFragment chatFragment;
private WiFiDirectServicesList servicesList;
private TextView statusTxtView;
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
statusTxtView = (TextView) findViewById(R.id.status_text);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
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, getMainLooper(), null);
startRegistrationAndDiscovery();
servicesList = new WiFiDirectServicesList();
getFragmentManager().beginTransaction()
.add(R.id.container_root, servicesList, "services").commit();
}
#Override
protected void onRestart() {
Fragment frag = getFragmentManager().findFragmentByTag("services");
if (frag != null) {
getFragmentManager().beginTransaction().remove(frag).commit();
}
super.onRestart();
}
#Override
protected void onStop() {
if (manager != null && channel != null) {
manager.removeGroup(channel, new ActionListener() {
#Override
public void onFailure(int reasonCode) {
Log.d(TAG, "Disconnect failed. Reason :" + reasonCode);
}
#Override
public void onSuccess() {
}
});
}
super.onStop();
}
/**
* Registers a local service and then initiates a service discovery
*/
private void startRegistrationAndDiscovery() {
Map<String, String> record = new HashMap<String, String>();
record.put(TXTRECORD_PROP_AVAILABLE, "visible");
WifiP2pDnsSdServiceInfo service = WifiP2pDnsSdServiceInfo.newInstance(
SERVICE_INSTANCE, SERVICE_REG_TYPE, record);
manager.addLocalService(channel, service, new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Added Local Service");
}
#Override
public void onFailure(int error) {
appendStatus("Failed to add a service");
}
});
discoverService();
}
private void discoverService() {
/*
* Register listeners for DNS-SD services. These are callbacks invoked
* by the system when a service is actually discovered.
*/
manager.setDnsSdResponseListeners(channel,
new DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice) {
// A service has been discovered. Is this our app?
if (instanceName.equalsIgnoreCase(SERVICE_INSTANCE)) {
// update the UI and add the item the discovered
// device.
WiFiDirectServicesList fragment = (WiFiDirectServicesList) getFragmentManager()
.findFragmentByTag("services");
if (fragment != null) {
WiFiDevicesAdapter adapter = ((WiFiDevicesAdapter) fragment
.getListAdapter());
WiFiP2pService service = new WiFiP2pService();
service.device = srcDevice;
service.instanceName = instanceName;
service.serviceRegistrationType = registrationType;
adapter.add(service);
adapter.notifyDataSetChanged();
Log.d(TAG, "onBonjourServiceAvailable "
+ instanceName);
}
}
}
}, new DnsSdTxtRecordListener() {
/**
* A new TXT record is available. Pick up the advertised
* buddy name.
*/
#Override
public void onDnsSdTxtRecordAvailable(
String fullDomainName, Map<String, String> record,
WifiP2pDevice device) {
Log.d(TAG,
device.deviceName + " is "
+ record.get(TXTRECORD_PROP_AVAILABLE));
}
});
// After attaching listeners, create a service request and initiate
// discovery.
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest,
new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Added service discovery request");
}
#Override
public void onFailure(int arg0) {
appendStatus("Failed adding service discovery request");
}
});
manager.discoverServices(channel, new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Service discovery initiated");
}
#Override
public void onFailure(int arg0) {
appendStatus("Service discovery failed");
}
});
}
#Override
public void connectP2p(WiFiP2pService service) {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = service.device.deviceAddress;
config.wps.setup = WpsInfo.PBC;
if (serviceRequest != null)
manager.removeServiceRequest(channel, serviceRequest,
new ActionListener() {
#Override
public void onSuccess() {
}
#Override
public void onFailure(int arg0) {
}
});
manager.connect(channel, config, new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Connecting to service");
}
#Override
public void onFailure(int errorCode) {
appendStatus("Failed connecting to service");
}
});
}
#Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
Log.d(TAG, readMessage);
(chatFragment).pushMessage("Buddy: " + readMessage);
break;
case MY_HANDLE:
Object obj = msg.obj;
(chatFragment).setChatManager((ChatManager) obj);
}
return true;
}
#Override
public void onResume() {
super.onResume();
receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
registerReceiver(receiver, intentFilter);
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
#Override
public void onConnectionInfoAvailable(WifiP2pInfo p2pInfo) {
Thread handler = null;
/*
* The group owner accepts connections using a server socket and then spawns a
* client socket for every client. This is handled by {#code
* GroupOwnerSocketHandler}
*/
if (p2pInfo.isGroupOwner) {
Log.d(TAG, "Connected as group owner");
try {
handler = new GroupOwnerSocketHandler(
((MessageTarget) this).getHandler());
handler.start();
} catch (IOException e) {
Log.d(TAG,
"Failed to create a server thread - " + e.getMessage());
return;
}
} else {
Log.d(TAG, "Connected as peer");
handler = new ClientSocketHandler(
((MessageTarget) this).getHandler(),
p2pInfo.groupOwnerAddress);
handler.start();
}
chatFragment = new WiFiChatFragment();
getFragmentManager().beginTransaction()
.replace(R.id.container_root, chatFragment).commit();
statusTxtView.setVisibility(View.GONE);
}
public void appendStatus(String status) {
String current = statusTxtView.getText().toString();
statusTxtView.setText(current + "\n" + status);
}
}
And the file for your AndroidManifast.xml should be the same and give these accesses
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="16" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Google Play filtering -->
<uses-feature android:name="android.hardware.wifi.direct" android:required="true"/>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".WiFiServiceDiscoveryActivity"
android:label="#string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
If you have any questions, let me respond as quickly as possible
SOURCE
WiFiDirectServiceDiscovery
Related
on line 370 i need a way to look for a string of 'f's' in the advertisement data from a TI CC2650. I found this template online but I'm looking for specific advertising data. Please let me know what string array I need to look at to find this.
package net.jmodwyer.beacon.beaconPoC;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Bundle;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.text.util.Linkify;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.location.LocationClient;
import net.jmodwyer.ibeacon.ibeaconPoC.R;
import org.altbeacon.beacon.Beacon;
import org.altbeacon.beacon.BeaconConsumer;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.RangeNotifier;
import org.altbeacon.beacon.Region;
import org.altbeacon.beacon.utils.UrlBeaconUrlCompressor;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
/**
* Adapted from original code written by D Young of Radius Networks.
* #author dyoung, jodwyer
*
*/
public class ScanActivity extends Activity implements BeaconConsumer,
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
// Constant Declaration
private static final String PREFERENCE_SCANINTERVAL = "scanInterval";
private static final String PREFERENCE_TIMESTAMP = "timestamp";
private static final String PREFERENCE_POWER = "power";
private static final String PREFERENCE_PROXIMITY = "proximity";
private static final String PREFERENCE_RSSI = "rssi";
private static final String PREFERENCE_MAJORMINOR = "majorMinor";
private static final String PREFERENCE_UUID = "uuid";
private static final String PREFERENCE_INDEX = "index";
private static final String PREFERENCE_LOCATION = "location";
private static final String PREFERENCE_REALTIME = "realTimeLog";
private static final String MODE_SCANNING = "Stop Scanning";
private static final String MODE_STOPPED = "Start Scanning";
protected static final String TAG = "ScanActivity";
/*
* Define a request code to send to Google Play services
* This code is returned in Activity.onActivityResult
*/
private final static int
CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private FileHelper fileHelper;
private BeaconManager beaconManager;
private Region region;
private int eventNum = 1;
// This StringBuffer will hold the scan data for any given scan.
private StringBuffer logString;
// Preferences - will actually have a boolean value when loaded.
private Boolean index;
private Boolean location;
private Boolean uuid;
private Boolean majorMinor;
private Boolean rssi;
private Boolean proximity;
private Boolean power;
private Boolean timestamp;
private String scanInterval;
// Added following a feature request from D.Schmid.
private Boolean realTimeLog;
// LocationClient for Google Play Location Services
LocationClient locationClient;
private ScrollView scroller;
private EditText editText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scan);
verifyBluetooth();
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
BeaconScannerApp app = (BeaconScannerApp)this.getApplication();
beaconManager = app.getBeaconManager();
//beaconManager.setForegroundScanPeriod(10);
region = app.getRegion();
beaconManager.bind(this);
locationClient = new LocationClient(this, this, this);
fileHelper = app.getFileHelper();
scroller = (ScrollView)ScanActivity.this.findViewById(R.id.scanScrollView);
editText = (EditText)ScanActivity.this.findViewById(R.id.scanText);
// Initialise scan button.
getScanButton().setText(MODE_STOPPED);
}
#Override
public void onResume() {
super.onResume();
beaconManager.bind(this);
}
#Override
public void onPause() {
super.onPause();
// Uncommenting the following leak prevents a ServiceConnection leak when using the back
// arrow in the Action Bar to come out of the file list screen. Unfortunately it also kills
// background scanning, and as I have no workaround right now I'm settling for the lesser of
// two evils.
// beaconManager.unbind(this);
}
public String getCurrentLocation() {
/** Default "error" value is set for location, will be overwritten with the correct lat and
* long values if we're ble to connect to location services and get a reading.
*/
String location = "Unavailable";
if (locationClient.isConnected()) {
Location currentLocation = locationClient.getLastLocation();
if (currentLocation != null) {
location = Double.toString(currentLocation.getLatitude()) + "," +
Double.toString(currentLocation.getLongitude());
}
}
return location;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_activity_actions, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public void onBeaconServiceConnect() {}
/**
*
* #param view
*/
public void onScanButtonClicked(View view) {
toggleScanState();
}
// Handle the user selecting "Settings" from the action bar.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.Settings:
// Show settings
Intent api = new Intent(this, AppPreferenceActivity.class);
startActivityForResult(api, 0);
return true;
case R.id.action_listfiles:
// Launch list files activity
Intent fhi = new Intent(this, FileHandlerActivity.class);
startActivity(fhi);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* Start and stop scanning, and toggle button label appropriately.
*/
private void toggleScanState() {
Button scanButton = getScanButton();
String currentState = scanButton.getText().toString();
if (currentState.equals(MODE_SCANNING)) {
stopScanning(scanButton);
} else {
startScanning(scanButton);
}
}
/**
* start looking for beacons.
*/
private void startScanning(Button scanButton) {
// Set UI elements to the correct state.
scanButton.setText(MODE_SCANNING);
((EditText)findViewById(R.id.scanText)).setText("");
// Reset event counter
eventNum = 1;
// Get current values for logging preferences
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
HashMap <String, Object> prefs = new HashMap<String, Object>();
prefs.putAll(sharedPrefs.getAll());
index = (Boolean)prefs.get(PREFERENCE_INDEX);
location = (Boolean)prefs.get(PREFERENCE_LOCATION);
uuid = (Boolean)prefs.get(PREFERENCE_UUID);
majorMinor = (Boolean)prefs.get(PREFERENCE_MAJORMINOR);
rssi = (Boolean)prefs.get(PREFERENCE_RSSI);
proximity = (Boolean)prefs.get(PREFERENCE_PROXIMITY);
power = (Boolean)prefs.get(PREFERENCE_POWER);
timestamp = (Boolean)prefs.get(PREFERENCE_TIMESTAMP);
scanInterval = (String)prefs.get(PREFERENCE_SCANINTERVAL);
realTimeLog = (Boolean)prefs.get(PREFERENCE_REALTIME);
// Get current background scan interval (if specified)
if (prefs.get(PREFERENCE_SCANINTERVAL) != null) {
beaconManager.setBackgroundBetweenScanPeriod(Long.parseLong(scanInterval));
}
logToDisplay("Scanning...");
// Initialise scan log
logString = new StringBuffer();
//Start scanning again.
beaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if (beacons.size() > 0) {
Iterator <Beacon> beaconIterator = beacons.iterator();
while (beaconIterator.hasNext()) {
Beacon beacon = beaconIterator.next();
// Debug - logging a beacon - checking background logging is working.
System.out.println("Logging another beacon.");
logBeaconData(beacon);
}
}
}
});
try {
beaconManager.startRangingBeaconsInRegion(region);
} catch (RemoteException e) {
// TODO - OK, what now then?
}
}
/**
* Stop looking for beacons.
*/
private void stopScanning(Button scanButton) {
try {
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
// TODO - OK, what now then?
}
String scanData = logString.toString();
if (scanData.length() > 0) {
// Write file
fileHelper.createFile(scanData);
// Display file created message.
Toast.makeText(getBaseContext(),
"File saved to:" + getFilesDir().getAbsolutePath(),
Toast.LENGTH_SHORT).show();
scanButton.setText(MODE_STOPPED);
} else {
// We didn't get any data, so there's no point writing an empty file.
Toast.makeText(getBaseContext(),
"No data captured during scan, output file will not be created.",
Toast.LENGTH_SHORT).show();
scanButton.setText(MODE_STOPPED);
}
}
/**
*
* #return reference to the start/stop scanning button
*/
private Button getScanButton() {
return (Button)findViewById(R.id.scanButton);
}
/**
*
* #param beacon The detected beacon
*/
private void logBeaconData(Beacon beacon) {
StringBuilder scanString = new StringBuilder();
if (index) {
scanString.append(eventNum++);
}
if (beacon.getServiceUuid() == 0xfeaa) {
if (beacon.getBeaconTypeCode() == 0x00) {
scanString.append(" Eddystone-UID -> ");
scanString.append(" Namespace : ").append(beacon.getId1());
scanString.append(" Identifier : ").append(beacon.getId2());
logEddystoneTelemetry(scanString, beacon);
} else if (beacon.getBeaconTypeCode() == 0x10) {
String url = UrlBeaconUrlCompressor.uncompress(beacon.getId1().toByteArray());
scanString.append(" Eddystone-URL -> " + url);
} else if (beacon.getBeaconTypeCode() == 0x20) {
scanString.append(" Eddystone-TLM -> ");
logEddystoneTelemetry(scanString, beacon);
}
} else {
// Just an old fashioned iBeacon or AltBeacon...
logGenericBeacon(scanString, beacon);
}
logToDisplay(scanString.toString());
scanString.append("\n");
// Code added following a feature request by D.Schmid - writes a single entry to a file
// every time a beacon is detected, the file will only ever have one entry as it will be
// recreated on each call to this method.
// Get current background scan interval (if specified)
if (realTimeLog) {
// We're in realtime logging mode, create a new log file containing only this entry.
fileHelper.createFile(scanString.toString(), "realtimelog.txt");
}
logString.append(scanString.toString());
}
/**
* Logs iBeacon & AltBeacon data.
*/
private void logGenericBeacon(StringBuilder scanString, Beacon beacon) {
// Comment stuff out for whatever reason
/*
if (location) {
scanString.append(" Location: ").append(getCurrentLocation()).append(" ");
}
`
*/
if (uuid) {
scanString.append(" UUID: ").append(beacon.getId1());
if (beacon.getId1().equals("ffffffff-ffff-ffff-ffff-ffffffffffff ")){
scanString.append("WE DID IT!!!!!!!!!!!");
}else{
scanString.append(" WE DID NOT DO IT =( ");
}
/*
if ((beacon.getId1()).equals ("f")){
scanString.append("WE DID IT!!!!!!!!!!!");
}else{
scanString.append(" WE DID NOT DO IT!!!!!!!!!!! ");
}
*/
}
// Making if statements to test for advertising data
/*
if (majorMinor) {
scanString.append(" Maj. Mnr.: ");
if (beacon.getId2() != null) {
scanString.append(beacon.getId2());
}
scanString.append("-");
if (beacon.getId3() != null) {
scanString.append(beacon.getId3());
}
}
if (rssi) {
scanString.append(" RSSI: ").append(beacon.getRssi());
}
if (proximity) {
scanString.append(" Proximity: ").append(BeaconHelper.getProximityString(beacon.getDistance()));
}
if (power) {
scanString.append(" Power: ").append(beacon.getTxPower());
}
if (timestamp) {
scanString.append(" Timestamp: ").append(BeaconHelper.getCurrentTimeStamp());
} */
}
private void logEddystoneTelemetry(StringBuilder scanString, Beacon beacon) {
// Do we have telemetry data?
if (beacon.getExtraDataFields().size() > 0) {
long telemetryVersion = beacon.getExtraDataFields().get(0);
long batteryMilliVolts = beacon.getExtraDataFields().get(1);
long pduCount = beacon.getExtraDataFields().get(3);
long uptime = beacon.getExtraDataFields().get(4);
scanString.append(" Telemetry version : " + telemetryVersion);
scanString.append(" Uptime (sec) : " + uptime);
scanString.append(" Battery level (mv) " + batteryMilliVolts);
scanString.append(" Tx count: " + pduCount);
}
}
/**
*
* #param line
*/
private void logToDisplay(final String line) {
runOnUiThread(new Runnable() {
public void run() {
editText.append(line + "\n");
// Temp code - don't really want to do this for every line logged, will look for a
// workaround.
Linkify.addLinks(editText, Linkify.WEB_URLS);
scroller.fullScroll(View.FOCUS_DOWN);
}
});
}
private void verifyBluetooth() {
try {
if (!BeaconManager.getInstanceForApplication(this).checkAvailability()) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth not enabled");
builder.setMessage("Please enable bluetooth in settings and restart this application.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
finish();
System.exit(0);
}
});
builder.show();
}
}
catch (RuntimeException e) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth LE not available");
builder.setMessage("Sorry, this device does not support Bluetooth LE.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
finish();
System.exit(0);
}
});
builder.show();
}
}
/* Location services code follows */
#Override
protected void onStart() {
super.onStart();
// Connect the client.
locationClient.connect();
}
#Override
protected void onStop() {
// Disconnect the client.
locationClient.disconnect();
super.onStop();
}
#Override
public void onConnected(Bundle dataBundle) {
// Uncomment the following line to display the connection status.
// Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
}
#Override
public void onDisconnected() {
// Display the connection status
Toast.makeText(this, "Disconnected. Please re-connect.",
Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
/* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(
this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
/*
* Thrown if Google Play services canceled the original
* PendingIntent
*/
} catch (IntentSender.SendIntentException e) {
// Log the error
e.printStackTrace();
}
} else {
/*
* If no resolution is available, display a dialog to the
* user with the error.
*/
Toast.makeText(getBaseContext(),
"Location services not available, cannot track device location.",
Toast.LENGTH_SHORT).show();
}
}
// Define a DialogFragment that displays the error dialog
public static class ErrorDialogFragment extends DialogFragment {
// Global field to contain the error dialog
private Dialog mDialog;
// Default constructor. Sets the dialog field to null
public ErrorDialogFragment() {
super();
mDialog = null;
}
// Set the dialog to display
public void setDialog(Dialog dialog) {
mDialog = dialog;
}
// Return a Dialog to the DialogFragment.
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return mDialog;
}
}
/*
* Handle results returned to the FragmentActivity
* by Google Play services
*/
#Override
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
// Decide what to do based on the original request code
switch (requestCode) {
case CONNECTION_FAILURE_RESOLUTION_REQUEST :
/*
* If the result code is Activity.RESULT_OK, try
* to connect again
*/
switch (resultCode) {
case Activity.RESULT_OK :
/*
* TODO - Try the request again
*/
break;
}
}
}
}
Need to cast to string first .toString
if (uuid) {
scanString.append(" UUID: ").append(beacon.getId1());
// Making if statements to look for all f's in advertising data
if (beacon.getId1().toString().equals(Str1)){
scanString.append("\nAlarm ACTIVATED\n");
}else{
scanString.append("\n Alarm NOT active\n");
}
}
I am trying to develope basic server app on Android using WiFi P2P and Network Service Discovery.
Unfortunatlly I stucked because I am still not able to add local service to my wifi p2p manager. Every time I am tring to run app onFailure method execute. Cannot find the reason.
import android.app.Activity;
import android.content.Context;
import android.content.IntentFilter;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
public class ServerMainActivity extends Activity
{
private IntentFilter mIntentFilter;
private WifiP2pManager mManager;
private WifiP2pManager.Channel mChannel;
private ServerBroadcastReceiver mReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_server_main);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), null);
mReceiver = new ServerBroadcastReceiver(mManager, mChannel, this);
startRegistration();
}
/** register the BroadcastReceiver with the intent values to be matched */
#Override
public void onResume() {
super.onResume();
mReceiver = new ServerBroadcastReceiver(mManager, mChannel, this);
registerReceiver(mReceiver, mIntentFilter);
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.server_main, menu);
return super.onCreateOptionsMenu(menu);
}
private void startRegistration() {
mManager.clearLocalServices(mChannel, new ActionListener() {
#Override
public void onFailure(int arg0) {
Log.d("Server Main Activity", "cannot clear local services " + arg0);
}
#Override
public void onSuccess() {
// TODO Auto-generated method stub
Log.d("Server Main Activity", "local services cleared.");
// Create a string map containing information about your service.
Map<String,String> record = new HashMap<String,String>();
record.put("listenport", "0");
record.put("buddyname", "John Doe" + (int) (Math.random() * 1000));
record.put("available", "visible");
// Service information. Pass it an instance name, service type
// _protocol._transportlayer , and the map containing
// information other devices will want once they connect to this one.
WifiP2pDnsSdServiceInfo serviceInfo =
WifiP2pDnsSdServiceInfo.newInstance("_SynchroMusic", "_tcp", record);
// Add the local service, sending the service info, network channel,
// and listener that will be used to indicate success or failure of
// the request.
mManager.addLocalService(mChannel, serviceInfo, new ActionListener() {
#Override
public void onSuccess() {
// Command successful! Code isn't necessarily needed here,
// Unless you want to update the UI or add logging statements.
Log.d("Server Main Activity", "local servica added.");
}
#Override
public void onFailure(int arg0) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
Log.d("Server Main Activity", "faliture" + arg0);
}
});
}
});
}
}
Most of this code is based on official android developer tutorials, so I guess it should work. Running cyanogenmod 11 (Android 4.4.2) on HTC One X.
Here is my BroadcastReceiver class if needed:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.util.Log;
public class ServerBroadcastReceiver extends BroadcastReceiver {
public ServerBroadcastReceiver() {
}
private WifiP2pManager mManager;
private WifiP2pManager.Channel mChannel;
private ServerMainActivity mActivity;
public ServerBroadcastReceiver(WifiP2pManager manager, Channel channel,
ServerMainActivity activity) {
super();
this.mManager = manager;
this.mChannel = channel;
this.mActivity = activity;
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
// Determine if Wifi P2P mode is enabled or not, alert
// the Activity.
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
//activity.setIsWifiP2pEnabled(true);
Log.d("ServerBroadcast", "Wifi on");
} else {
//activity.setIsWifiP2pEnabled(false);
Log.d("ServerBroadcast", "Wifi off");
}
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// The peer list has changed! We should probably do something about
// that.
Log.d("ServerBroadcast", "peers Changed action");
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
// Connection state changed! We should probably do something about
// that.
Log.d("ServerBroadcast", "Con Changed");
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
// DeviceListFragment fragment = (DeviceListFragment) activity.getFragmentManager()
// .findFragmentById(R.id.frag_list);
//fragment.updateThisDevice((WifiP2pDevice) intent.getParcelableExtra(
/// WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
Log.d("ServerBroadcast", "Dev Changed");
}
//throw new UnsupportedOperationException("Not yet implemented " + action);
else throw new UnsupportedOperationException("Not yet implemented " + action);
}
}
When line
//throw new UnsupportedOperationException("Not yet implemented " + action);
is not commented it throws an error
Not yet implementedandroid.net.wifi.p2p.STATE_CHANGED
You must wait for WIFI_P2P_STATE_ENABLED and then register your service.
I coded an application to record user's location periodically (in the background). I used ActivityRecognitionClient. When activity is received it is compared to previous activity state and is recorded (or not) according to evaluation.
It's working as intended as long as my phone is awake. (log messages appear periodically in LogCat view on eclipse) Whenever screen goes off and device goes into stand by status it stops receiving activity recognition calls. On the other hand, I installed the app on my tablet too, and it keeps updating even the device goes into stand by status. (My phone is General Mobile Discovery btw)
I've been searching web (including stackoverflow questions) for 3 days and haven't been able to find anything that works for me so far. I'd appreciate any help... Thanks...
Following is my applications related code:
AndroidManifest.xml (some permissions are there even if not needed, they are probably leftovers from unsuccessful trials to fix the issue)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.o3n.android.familywathcer"
android:installLocation="internalOnly"
android:versionCode="2"
android:versionName="1.0.1" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>
<permission android:name="org.o3n.android.familywathcer.permission.MAPS_RECEIVE" android:protectionLevel="signature"/>
<uses-permission android:name="org.o3n.android.familywathcer.permission.MAPS_RECEIVE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="***maps api key *****"/>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity
android:name="org.o3n.android.familywathcer.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:label="Settings" android:name=".SettingsActivity">
<intent-filter>
<action android:name="org.o3n.android.familywatcher.SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service android:enabled="true" android:name=".FamilyWatcherService" />
<service android:name=".ActivityRecognitionService" />
<receiver android:name=".StartFamilyWatcherServiceAtBootReceiver"
android:enabled="true"
android:exported="true"
android:label="StartFamilyWatcherServiceAtBootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
StartFamilyWatcherServiceAtBootReceiver.java (This receiver starts the FamilyWatcherService.java on device boot, also applications MainActivity.java class calls the FamilyWatcherService so it starts running when first installed.)
public class StartFamilyWatcherServiceAtBootReceiver extends BroadcastReceiver {
private static final String TAG = "o3nWatcherLog";
#Override
public void onReceive(Context context, Intent intent) {
//Toast.makeText(context, "StartFamilyWatcherServiceAtBootReceiver called", Toast.LENGTH_SHORT).show();
Log.d(TAG, "StartFamilyWatcherServiceAtBootReceiver onRecieve");
SettingsRetriever.getInstance(context);
Intent serviceIntent = new Intent(context, FamilyWatcherService.class);
context.startService(serviceIntent);
}
}
FamilyWatcherService.java (This service connects to ActivityRecognitionClient and registers a PendingIntend to be called with activity updates. When it works ActivityRecognitionService.onHandleIntend() method is called)
public class FamilyWatcherService extends Service implements ConnectionCallbacks, OnConnectionFailedListener {
private int period;
private static ActivityRecognitionClient arclient;
private static PendingIntent pIntent;
private static AlarmManager alarmManager;
private static PendingIntent alarmPI;
private static final String TAG = "o3nWatcherLog";
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Log.d(TAG, "FamilyWatcherService onCreate");
period = SettingsRetriever.getInstance().getPeriod() * 60 * 1000;
}
#Override
public void onDestroy() {
Log.d(TAG, "FamilyWatcherService onDestroy");
if(arclient!=null){
arclient.removeActivityUpdates(pIntent);
arclient.disconnect();
}
}
#Override
public void onStart(Intent intent, int startid) {
Log.d(TAG, "FamilyWatcherService onStart");
processStart();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "FamilyWatcherService onStartCommand");
processStart();
return Service.START_STICKY;
}
public void processStart() {
int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
if (result != ConnectionResult.SUCCESS) {
Log.d("o3nWatcherLog", "Google Play service is not available (status=" + result + ")");
}
else{
arclient = new ActivityRecognitionClient(getApplicationContext(), this, this);
arclient.connect();
}
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
Log.d("o3nWatcherLog","Google activity recognition services connection failed");
}
#Override
public void onConnected(Bundle arg0) {
Log.d("o3nWatcherLog", "FamilyWathcerService onConnected method called...");
Intent intent = new Intent(this, ActivityRecognitionService.class);
pIntent = PendingIntent.getService(getApplicationContext(), 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);
arclient.requestActivityUpdates(period, pIntent);
}
#Override
public void onDisconnected() {
Log.d("o3nWatcherLog", "Google activity recognition services disconnected");
}
}
ActivityRecognitionService.java (This service's onHandleIntent() method is called by Activity Recognition updates)
package org.o3n.android.familywathcer;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import org.json.JSONException;
import org.json.JSONObject;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.location.ActivityRecognitionResult;
import com.google.android.gms.location.DetectedActivity;
import com.google.android.gms.location.LocationClient;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
public class ActivityRecognitionService extends IntentService implements ConnectionCallbacks, OnConnectionFailedListener {
private String TAG = "o3nWatcherLog";
private Context context;
private static int activityEvaluation = 0;
//TODO MAKE THESE PREFERENCES
private static final int MIN_RECORD_DISTANCE = 750;
private static final int MIN_RECORD_INTERVAL = 10 * 1000 * 60;
private static final int MIN_POST_INTERVAL = 2 * 1000 * 60;
//END MAKE THESE PREFERENCES
private LocationClient locationClient;
private static Location lastRecordedLocation;
private static int previousActivityCode = DetectedActivity.UNKNOWN;
private int activityCode = -1000;
private int activityConfidence = -1000;
public ActivityRecognitionService() {
super("My Activity Recognition Service");
}
#Override
protected void onHandleIntent(Intent intent) {
if(ActivityRecognitionResult.hasResult(intent)){
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
Log.i(TAG, getType(result.getMostProbableActivity().getType()) +"t" + result.getMostProbableActivity().getConfidence());
this.context = getApplicationContext();
Log.d("o3nWatcherLog", "ActivityRecognitionService onHandleIntent called...");
activityConfidence = result.getMostProbableActivity().getConfidence();
activityCode = result.getMostProbableActivity().getType();
Log.d("o3nWatcherLog", " ACTIVITY CODE : " + activityCode + " ACTIVITY CONFIDENCE : " + activityConfidence);
// Evaluate the avtivity recognition result
evaluateActivityResult();
// Get current location
// check Google Play service APK is available and up to date.
final int googlePlayServiceAvailable = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (googlePlayServiceAvailable != ConnectionResult.SUCCESS) {
Log.d("o3nWatcherLog", "Google Play service is not available (status=" + result + ")");
}
else {
locationClient = new LocationClient(context, this, this);
locationClient.connect();
}
}
}
// This method is only used in a log line to have readable status in logs
private String getType(int type){
if(type == DetectedActivity.UNKNOWN)
return "UNKNOWN";
else if(type == DetectedActivity.IN_VEHICLE)
return "IN_VEHICLE";
else if(type == DetectedActivity.ON_BICYCLE)
return "ON_BICYCLE";
else if(type == DetectedActivity.ON_FOOT)
return "ON_FOOT";
else if(type == DetectedActivity.STILL)
return "STILL";
else if(type == DetectedActivity.TILTING)
return "TILTING";
else
return "";
}
private void evaluateActivityResult() {
// (Based on previousActivityCode and current activityCode
// assign a value to activityEvaluation)
// compare activityCode to previousActivityCode
activityEvaluation = ...;
previousActivityCode = activityCode;
}
private void actOnEvaluation(Location loc) {
// Based on activityEvaluation decide to post or not
if ( activityEvaluation ....)
prepareTheLocationJsonAndRecord(loc);
}
private void prepareTheLocationJsonAndRecord(Location loc) {
// Record the location
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
//Toast.makeText(context, "Google location services connection failed", Toast.LENGTH_LONG).show();
Log.d("o3nWatcherLog","Google location services connection failed");
}
#Override
public void onDisconnected() {
//Toast.makeText(context, "Google location services disconnected", Toast.LENGTH_LONG).show();
Log.d("o3nWatcherLog", "Google location services disconnected");
}
#Override
public void onConnected(Bundle arg0) {
//Toast.makeText(context, "Google location services connected", Toast.LENGTH_LONG).show();
Log.d("o3nWatcherLog", "Google location services connected");
Location loc = locationClient.getLastLocation();
Log.d("o3nWatcherLog", "location= " + loc.toString());
if (loc!=null)
actOnEvaluation(loc);
}
}
I assume you need to set up some Power Wake lock to make phone to process GPS locations even in "sleep" mode. Like WiFi lock, etc. When I did something like that I used:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm!=null){
pmWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK+PowerManager.ON_AFTER_RELEASE, APP_TAG);
pmWakeLock.acquire();
}
But that was inside of a GPS-tracking activity. You need to alter params of newWakeLock for your needs. Maybe the service you are using has some code about it so you just need to declare using of WakeLock permission in the Manifest first.
I'm looking for a way to send data between my Android Device and Google Glass that doesn't rely on Cloud API's. Is this supported? I see the Bluetooth connections in the My Glass app, which makes me think it can be done. Is there an example source code that shows how this is done? Or do I have to decompile the MyGlass app to figure it out?
Is there a preferred method for doing this kind of data transfer? Ideally I'd like to transfer data in both directions.
Ok, for the requesters....
EDIT: The code below still works, but I've put it into a git repo for those who are interested...
https://github.com/NathanielWaggoner/GoogleGlassBlutooth
Here is my Bluetooth Host/Client code. It's not perfect - You're going to need some patience, and there are some bugs on reconnection and such, but it does work. I've been sending data up to Glass From the Hand Held and driving UI updates (publishing live cards, updating live cards etc...) for about three days using this now.
Host:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
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.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.widget.TextView;
public class BluetoothHost extends Activity {
public static String msgToSend="";
public static final int STATE_CONNECTION_STARTED = 0;
public static final int STATE_CONNECTION_LOST = 1;
public static final int READY_TO_CONN = 2;
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
// our last connection
ConnectedThread mConnectedThread;// = new ConnectedThread(socket);
// track our connections
ArrayList<ConnectedThread> mConnThreads;
// bt adapter for all your bt needs (where we get all our bluetooth powers)
BluetoothAdapter myBt;
// list of sockets we have running (for multiple connections)
ArrayList<BluetoothSocket> mSockets = new ArrayList<BluetoothSocket>();
// list of addresses for devices we've connected to
ArrayList<String> mDeviceAddresses = new ArrayList<String>();
// just a name, nothing more...
String NAME="G6BITCHES";
// We can handle up to 7 connections... or something...
UUID[] uuids = new UUID[2];
// some uuid's we like to use..
String uuid1 = "05f2934c-1e81-4554-bb08-44aa761afbfb";
String uuid2 = "c2911cd0-5c3c-11e3-949a-0800200c9a66";
// just a tag..
String TAG = "G6 Bluetooth Host Activity";
// constant we define and pass to startActForResult (must be >0), that the system passes back to you in your onActivityResult()
// implementation as the requestCode parameter.
int REQUEST_ENABLE_BT = 1;
AcceptThread accThread;
TextView connectedDevices;
Handler handle;
BroadcastReceiver receiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// the activity for this is pretty stripped, just a basic selection ui....
setContentView(R.layout.activity_main);
uuids[0] = UUID.fromString(uuid1);
uuids[1] = UUID.fromString(uuid2);
connectedDevices = (TextView) findViewById(R.id.connected_devices_values);
handle = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case STATE_CONNECTION_STARTED:
connectedDevices.setText(msg.getData().getString("NAMES"));
break;
case STATE_CONNECTION_LOST:
connectedDevices.setText("");
startListening();
break;
case READY_TO_CONN:
startListening();
default:
break;
}
}
};
// ....
myBt = BluetoothAdapter.getDefaultAdapter();
// run the "go get em" thread..
accThread = new AcceptThread();
accThread.start();
}
public void startListening() {
if(accThread!=null) {
accThread.cancel();
}else if (mConnectedThread!= null) {
mConnectedThread.cancel();
} else {
accThread = new AcceptThread();
accThread.start();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class AcceptThread extends Thread {
private BluetoothServerSocket mmServerSocket;
BluetoothServerSocket tmp;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
tmp = myBt.listenUsingInsecureRfcommWithServiceRecord(NAME, uuids[0]);
} catch (IOException e) { }
mmServerSocket = tmp;
}
public void run() {
Log.e(TAG,"Running?");
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
e.printStackTrace();
break;
}
// If a connection was accepted
if (socket != null) {
try {
mmServerSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(socket);
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
mmServerSocket.close();
Message msg = handle.obtainMessage(READY_TO_CONN);
handle.sendMessage(msg);
} catch (IOException e) { }
}
}
private void manageConnectedSocket(BluetoothSocket socket) {
// start our connection thread
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
// Send the name of the connected device back to the UI Activity
// so the HH can show you it's working and stuff...
String devs="";
for(BluetoothSocket sock: mSockets) {
devs+=sock.getRemoteDevice().getName()+"\n";
}
// pass it to the UI....
Message msg = handle.obtainMessage(STATE_CONNECTION_STARTED);
Bundle bundle = new Bundle();
bundle.putString("NAMES", devs);
msg.setData(bundle);
handle.sendMessage(msg);
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
//byte[] blah = ("System Time:" +System.currentTimeMillis()).getBytes();
if(!msgToSend.equals("")) {
Log.e(TAG,"writing!");
write(msgToSend.getBytes());
setMsg("");
}
Thread.sleep(1000);
} catch (Exception e) {
Log.e(TAG, "disconnected", e);
connectionLost();
}
}
}
public void connectionLost() {
Message msg = handle.obtainMessage(STATE_CONNECTION_LOST);
handle.sendMessage(msg);
}
/**
* Write to the connected OutStream.
* #param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
connectionLost();
}
}
public void cancel() {
try {
mmSocket.close();
Message msg = handle.obtainMessage(READY_TO_CONN);
handle.sendMessage(msg);
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
public static synchronized void setMsg(String newMsg) {
msgToSend = newMsg;
}
public static class HostBroadRec extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle b= intent.getExtras();
String vals ="";
for(String key: b.keySet()) {
vals+=key+"&"+b.getString(key)+"Z";
}
BluetoothHost.setMsg(vals);
}
}
}
Client:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
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.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
public class BluetoothClient extends Activity {
public static final int READY_TO_CONN =0;
public static final int CANCEL_CONN =1;
public static final int MESSAGE_READ =2;
// holds the bluetooth names/ids that we're associated with.
ArrayAdapter<String> btArray;
// bt adapter for all your bt needs
BluetoothAdapter myBt;
String NAME="G6BITCHES";
String TAG = "G6 Bluetooth Slave Activity";
UUID[] uuids = new UUID[2];
// some uuid's we like to use..
String uuid1 = "05f2934c-1e81-4554-bb08-44aa761afbfb";
String uuid2 = "c2911cd0-5c3c-11e3-949a-0800200c9a66";
// DateFormat df = new DateFormat("ddyyyy")
ConnectThread mConnThread;
Spinner devices;
Handler handle;
// constant we define and pass to startActForResult (must be >0), that the system passes back to you in your onActivityResult()
// implementation as the requestCode parameter.
int REQUEST_ENABLE_BT = 1;
// bc for discovery mode for BT...
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
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);
// Add the name and address to an array adapter to show in a ListView
if(device!= null) {
if(device.getName().contains("Nexus")) {
} else {
btArray.add(device.getName() + "\n" + device.getAddress());
}
}
update();
}
}
};
Context ctx;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// publishCards(this);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
ctx = this;
handle = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case READY_TO_CONN:
mConnThread=null;
update();
break;
case CANCEL_CONN:
break;
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
Log.e(TAG,"received: "+readMessage);
if (readMessage.length() > 0) {
// do soemthing...
}
// updateCards(ctx, readMessage);
// update()
// mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage);
break;
default:
break;
}
}
};
btArray = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, android.R.id.text1);
btArray.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
uuids[0] = UUID.fromString(uuid1);
uuids[1] = UUID.fromString(uuid2);
// spinner for displaying available devices for pairing
devices = (Spinner) findViewById(R.id.devices_spinner);
devices.setAdapter(btArray);
// use the same UUID across an installation
// should allow clients to find us repeatedly
myBt = BluetoothAdapter.getDefaultAdapter();
if (myBt == null) {
Toast.makeText(this, "Device Does not Support Bluetooth", Toast.LENGTH_LONG).show();
}
else if (!myBt.isEnabled()) {
// we need to wait until bt is enabled before set up, so that's done either in the following else, or
// in the onActivityResult for our code ...
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
} else {
detectAndSetUp();
}
setContentView(R.layout.bluetooth_activity_layout);
}
#Override
public void onDestroy() {
unregisterReceiver(mReceiver);
super.onDestroy();
}
#Override
protected void onActivityResult (int requestCode, int resultCode, Intent data){
if(requestCode == REQUEST_ENABLE_BT) {
if (resultCode != RESULT_OK) {
Toast.makeText(this, "Failed to enable Bluetooth", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Bluetooth Enabled", Toast.LENGTH_LONG).show();
detectAndSetUp();
}
}
}
private void detectAndSetUp() {
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
Set<BluetoothDevice> pairedDevices = myBt.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
if(device.getName().contains("Nexus")) {
} else {
btArray.add(device.getName() + "\n" + device.getAddress());
}
// Add the name and address to an array adapter to show in a ListView
// btArray.add(device.getName() + "\n" + device.getAddress());
// update();
}
}
myBt.startDiscovery();
}
public void update() {
devices = (Spinner) findViewById(R.id.devices_spinner);
devices.setAdapter(btArray);
devices.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int position, long id) {
if(mConnThread!=null) {
Log.e(TAG,"Canceling old connection, and starting new one.");
mConnThread.cancel();
} else {
Log.e(TAG,"got a thing...");
String str = ((TextView)arg1).getText().toString();
Log.e(TAG,"tots: "+str);
String[] vals = str.split("\n");
Log.e(TAG,"mac: "+vals[1]);
BluetoothDevice dev = myBt.getRemoteDevice(vals[1]);
mConnThread = new ConnectThread(dev);
mConnThread.run();
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.bluetooth, menu);
return true;
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
Log.e(TAG,"ConnectThread start....");
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// this seems to work on the note3...
// you can remove the Insecure if you want to...
tmp = device.createInsecureRfcommSocketToServiceRecord(uuids[0]);
// Method m;
// this is an approach I've seen others use, it wasn't nescesary for me,
// but your results may vary...
// m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class});
// tmp = (BluetoothSocket) m.invoke(device, 1);
// } catch (NoSuchMethodException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// } catch (IllegalArgumentException e2) {
// // TODO Auto-generated catch block
// e2.printStackTrace();
// } catch (IllegalAccessException e3) {
// // TODO Auto-generated catch block
// e3.printStackTrace();
// } catch (InvocationTargetException e4) {
// // TODO Auto-generated catch block
// e4.printStackTrace();
// }
// if(tmp.isConnected()) {
// break
// }
} catch (Exception e) {
Log.e(TAG,"Danger Will Robinson");
e.printStackTrace();
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
myBt.cancelDiscovery();
Log.e(TAG,"stopping discovery");
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
Log.e(TAG,"connecting!");
mmSocket.connect();
} catch (IOException connectException) {
Log.e(TAG,"failed to connect");
// Unable to connect; close the socket and get out
try {
Log.e(TAG,"close-ah-da-socket");
mmSocket.close();
} catch (IOException closeException) {
Log.e(TAG,"failed to close hte socket");
}
Log.e(TAG,"returning..");
return;
}
Log.e(TAG,"we can now manage our connection!");
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(mmSocket);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
Message msg = handle.obtainMessage(READY_TO_CONN);
handle.sendMessage(msg);
} catch (IOException e) { }
}
}
public void manageConnectedSocket(BluetoothSocket mmSocket) {
ConnectedThread t = new ConnectedThread(mmSocket);
t.start();
// manage your socket... I'll probably do a lot of the boiler plate here later
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// byte[] blah = ("System Time:" +System.currentTimeMillis()).getBytes();
// write(blah);
// Thread.sleep(1000);
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
handle.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
// .sendToTarget();
} catch (Exception e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// break;
}
}
}
public void connectionLost() {
Message msg = handle.obtainMessage(CANCEL_CONN);
// Bundle bundle = new Bundle();
// bundle.putString("NAMES", devs);
// msg.setData(bundle);
handle.sendMessage(msg);
}
/**
* Write to the connected OutStream.
* #param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
// mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
// .sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
Host Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="transapps.android_bluetooth_host"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name="transapps.android_bluetooth_host.BluetoothHost"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".BluetoothHost$HostBroadRec" >
<intent-filter>
<action android:name="transapps.g6.new.alert" />
</intent-filter>
</receiver>
</application>
</manifest>
Client Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="transapps.android_blutooth"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name="transapps.android_blutooth.BluetoothClient"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I'll leave the UI as an exercise to the reader.
There is no preferred method, but if you're looking to do it wirelessly, a Bluetooth 3.0 RFCOMM does work.
If you provide more specifics about the problem you're trying to solve in your question, I'll be able to provide a more specific answer.
Several things I noticed when following this solution (awesome work by the way!)
1) I could only create a bluetooth connection when my phone and the Google Glass were not already paired through the MyGlass app - If you are having trouble establishing a connection, try forgetting that pairing.
2) The Glass API does not support controlling your bluetooth connection through intents using commands like
Intent discoveryIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoveryIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, DISCOVER_DURATION);
startActivityForResult(discoveryIntent, REQUEST_BLU);
In order to make the Glass headset discoverable (rather than the phone it is connecting to), I needed to follow solutions similar to those like user4934624 provided at this question and shantanu gave at this question. I invoked a hidden method to access bluetooth functionality directly. Warning: the hidden method seems to have been there for years, but there is no guarantee it will continue to be in future APIs.
// this method allows us to make the device discoverable without alerting the users
// NOTE!!!! This uses a hidden method, so it may be removed from the API in the future
public void makeDiscoverable (){
Class <?> baClass = BluetoothAdapter.class;
Method[] methods = baClass.getDeclaredMethods();
// we want to use method setScanMode(int mode, int duration)
// there are 2 setScanModes
// so select the first setScanMode you see
// test to see which method is the one we want
//for (int i = 0; i<50; i++) {Log.d(Integer.toString(i), methods[i].getName());}
//I had trouble calling the first setScanMode, so I called the second.
// I need to pass in a discoverable time, but it stays discoverable indefinitely
// Thus you must turn off the setScanMode as soon as the connection is established
// I should probably write in some other security stuff to turn it off if connection fails
// maybe a timer running on a different thread?
Method mSetScanMode = methods[38];
try {
mSetScanMode.invoke(myBt, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,300);
//mSetScanMode.invoke(myBt, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
} catch (Exception e) {
Log.e("discoverable", e.getMessage());
}
}
// this method allows us to make the device not discoverable without alerting the user
// NOTE!!!! This uses a hidden method, so it may be removed from the API in the future
public void makeNotDiscoverable (){
// see notes for makeDiscoverable
Class <?> baClass = BluetoothAdapter.class;
Method [] methods = baClass.getDeclaredMethods();
Method mSetScanMode = methods[38];
try {
mSetScanMode.invoke(myBt, BluetoothAdapter.SCAN_MODE_CONNECTABLE,300);
} catch (Exception e) {
Log.e("discoverable", e.getMessage());
}
}
Note that I first ran a test that output the names of all the methods in the class I mirrored; that allowed me to narrow my search for which method I wanted to use.
The JoeGlass app for android claims to be a replacement for MyGlass. It will talk to your glass directly, using a bluetooth connection. I have not tried yet it but it is open source (github), so if it works, you are good.
My book Beginning Google Glass Development has a full chapter on this topic, with fully working example code on using Bluetooth and socket to transfer data between Glass and Android (or iOS) devices.
The book is available at amazon: http://www.amazon.com/Beginning-Google-Glass-Development-Jeff/dp/1430267887
and the source code is available for download at http://www.apress.com/downloadable/download/sample/sample_id/1562/
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