I use v7 support library MediaRouter for switching routes between phone's speaker and bluetooth device.
And sometimes it works strange, for example, when I turn off the bluetooth, corresponding route seems to be removed (playback switches to the speaker), but my application doesn't receive any callback about it. And moreover, when I manually get all the routes via MediaRouter.getRoutes(), it returns that bluetooth route, but when I try to switch to it, it seems to be selected, but actually playback still goes through the speaker.
I tried all the flags CALLBACK_FLAG_FORCE_DISCOVERY, CALLBACK_FLAG_REQUEST_DISCOVERY etc, without result. Only phone reboot helps. Any suggestions?
I used Android 4.2, 4.4.
UPDATE, code sample:
....
private MediaRouter mMediaRouter;
private MediaRouter.Callback mMediaRouterCallback = new MediaRouter.Callback(){
#Override
public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) {
super.onRouteAdded(router, route);
refreshRoutes();
Log.i(TAG, "Route added ==> " + route.getName());
}
#Override
public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo route) {
super.onRouteRemoved(router, route);
refreshRoutes();
Log.i(TAG, "Route removed ==> " + route.getName());
}
#Override
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo route) {
super.onRouteSelected(router, route);
Log.i(TAG, "Route selected ==> " + route.getName());
refreshRoutes();
}
#Override
public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo route) {
super.onRouteUnselected(router, route);
Log.i(TAG, "Route UNselected ==> " + route.getName());
refreshRoutes();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRoutesList = (ListView) findViewById(R.id.routesList);
mRoutesList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String routeName = mRoutesAdapter.getItem(i);
List<MediaRouter.RouteInfo> routes = mMediaRouter.getRoutes();
for (MediaRouter.RouteInfo rout : routes){
if (rout.getName().equals(routeName)){
mMediaRouter.selectRoute(rout);
}
}
}
});
mMediaRouter = MediaRouter.getInstance(this);
mMediaRouter.addCallback(
new MediaRouteSelector.Builder()
.addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
.build(),
mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
mRoutesAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, 0);
mRoutesList.setAdapter(mRoutesAdapter);
refreshUi();
}
#Override
protected void onDestroy() {
mMediaRouter.removeCallback(mMediaRouterCallback);
super.onDestroy();
}
private void refreshRoutes(){
mRoutesAdapter.clear();
MediaRouter.RouteInfo selectedRoute = mMediaRouter.getSelectedRoute();
List<MediaRouter.RouteInfo> routes = mMediaRouter.getRoutes();
for (MediaRouter.RouteInfo rout : routes){
if (rout == selectedRoute)
mRoutesAdapter.add(rout.getName() + " [selected]");
else
mRoutesAdapter.add(rout.getName());
}
mRoutesAdapter.notifyDataSetChanged();
}
Using #Xaver's suggestion in the question comments, I put all of the MediaRouting in a Service. I got everything working how it was before the service but the same error was occurring. When I returned to an activity, after one switch from the wired to the BlueTooth speaker, the MediaRouter would get stuck on the wired speaker despite saying that the current route was the Bluetooth speaker.
Switching from android.support.v7.media.MediaRouter to the android.media.MediaRouter and refactoring my code a little everything worked perfectly. Hard to say if moving the routing to a service was part of the combination but I got it working (after ~50 hours of tinkering with everything)
The unfortunate thing with android.media.MediaRouter is it doesn't have a getRoutes method, but nothing a little Googleing couldn't handle! Since I found it a pain to figure this out from the docs, since everything is referencing the v7 library, below is how to get the MediaRouter and select a route.
MediaRouter mr = (MediaRouter)this.getSystemService(this.MEDIA_ROUTER_SERVICE);
mr.selectRoute(mr.ROUTE_TYPE_LIVE_AUDIO, mr.getRouteAt(0));
Hopefully this helps someone!
Related
Wifi P2P service discovery is not behaving as expected. I am seeing intermittent issues where the DNSSD listeners are not called always and hence I have no clue of nearby devices running the same app. I am using the following two APIs - one to register a service to be discovered by other devices and the other to discover the nearby services running on other devices. Any idea if I am doing anything wrong here or is there some specific sequence of other android API calls that need to be made before I call these APIs to ensure that the listeners are always called whenever there is a new service registered or even if a service is registered before we call the API to discover the local services.
API to register a local service:
private void registerService() {
Map<String, String> values = new HashMap<String, String>();
values.put("name", "Steve");
values.put("port", "8080");
WifiP2pServiceInfo srvcInfo = WifiP2pDnsSdServiceInfo.newInstance(mMyDevice.deviceName, "_http._tcp", values);
manager.addLocalService(channel, srvcInfo, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Toast.makeText(WiFiDirectActivity.this, "Local service added successfully",
Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(int reasonCode) {
Toast.makeText(WiFiDirectActivity.this, "Local service addition failed : " + reasonCode,
Toast.LENGTH_SHORT).show();
}
});
}
API to discover local services:
public void discoverService() {
manager.clearServiceRequests(channel, null);
DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
#Override
/* Callback includes:
* fullDomain: full domain name: e.g "printer._ipp._tcp.local."
* record: TXT record data as a map of key/value pairs.
* device: The device running the advertised service.
*/
public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
}
};
DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) {
Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
}
};
manager.setDnsSdResponseListeners(channel, servListener, txtListener);
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest, new ActionListener() {
#Override
public void onSuccess() {
// Success!
Log.d(TAG, "addServiceRequest success");
}
#Override
public void onFailure(int code) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
Log.d(TAG, "addServiceRequest failure with code " + code);
}
});
manager.discoverServices(channel, new ActionListener() {
#Override
public void onSuccess() {
// Success!
Log.d(TAG, "discoverServices success");
}
#Override
public void onFailure(int code) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
if (code == WifiP2pManager.P2P_UNSUPPORTED) {
Log.d(TAG, "P2P isn't supported on this device.");
} else {
Log.d(TAG, "discoverServices failure");
}
}
});
}
Note: manager & channel are initialized as
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(this, getMainLooper(), null);
WifiP2p (in general):
Some time ago I was developing an application with a pretty complex network connectivity system based on WifiP2p with Service Broadcasting/Discovery. And based on that experience I already wrote few posts here on SO about how difficult, wearing and problematic that is. Here are two of them (they are quite full of the inside knowledge I acquired about WifiP2p with Service Discovery, and WifiP2p itself):
Why is discovering peers for Android WifiDirect so unreliable
Wi-fi P2P. Inform all peers available of some event
I would advise you to read both of my answers (even though they are focused a bit more on the WifiP2p itself). They should give you some perspective on the things you should be looking for when working with the WifiP2p Service Discovery.
I can easily say that if you want to build an efficient, relatively reliable and robust WifiP2p connection system (especially with Service Discovery), you will have to work your ass off.
WifiP2p Service Discovery:
To better answer your exact question, I will tell you what I did (different from you) to make my Service Discovery work pretty reliably.
1. Broadcasting Service:
First of all: before registering your Service (with addLocalService method) you should use the WifiP2pManager's clearLocalServices method. And it is important, that you should only call addLocalService if the listener passed in the clearLocalServices returned with the onSuccess callback.
Although this sets up the broadcasting pretty nicely, I found that other nodes were not always able to detect the broadcasted service (especially when those nodes weren't already actively detecting services at the moment of registering your local Service - but they "joined" later). I couldn't find a way to fix this issue 100% reliably. And believe me I was trying probably everything WifiP2p-related. And no, the clearLocalServices-addLocalService sequence wasn't really giving satisfying results. Or more so: doing something different was working much better. What I decided to do, was after I successfully added local service (onSuccess callback from addLocalService), I started a Thread that would periodically call WifiP2pManager's method discoverPeers. That seemed to be forcing to rebroadcast all the service information.
So... basically the base of your broadcasting code should look more-less like this (bare in mind that every single piece of code I will post here is stripped-off of all "checks" if the network connectivity system is in the right state, you should design them yourself to fit your solution the best):
public void startBroadcastingService(){
mWifiP2pManager.clearLocalServices(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
mWifiP2pManager.addLocalService(mWifiP2pChannel, mWifiP2pServiceInfo,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
// service broadcasting started
mServiceBroadcastingHandler
.postDelayed(mServiceBroadcastingRunnable,
SERVICE_BROADCASTING_INTERVAL);
}
#Override
public void onFailure(int error) {
// react to failure of adding the local service
}
});
}
#Override
public void onFailure(int error) {
// react to failure of clearing the local services
}
});
}
where the mServiceBroadcastingRunnable should be:
private Runnable mServiceBroadcastingRunnable = new Runnable() {
#Override
public void run() {
mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
}
#Override
public void onFailure(int error) {
}
});
mServiceBroadcastingHandler
.postDelayed(mServiceBroadcastingRunnable, SERVICE_BROADCASTING_INTERVAL);
}
};
2. Discovering Service:
For the discovering of your service I used similar approach. Both with the setting up the discovering, and with trying to force "rediscovery" of services.
Setting up was performed with the sequence of the following three WifiP2pManager's methods:
removeServiceRequest, addServiceRequest, discoverServices
They were called in this exact order and a particular method (second or the third one to be exact) has been called only after the previous one had "returned" with the onSuccess callback.
The rediscovery of services was being performed with the intuitive method (just by repeating the mentioned sequence: removeServiceRequest -> addServiceRequest -> discoverServices).
The base of my code looked more-less like this (to start Service Discovery I would first call prepareServiceDiscovery() and then startServiceDiscovery()):
public void prepareServiceDiscovery() {
mWifiP2pManager.setDnsSdResponseListeners(mWifiP2pChannel,
new WifiP2pManager.DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice) {
// do all the things you need to do with detected service
}
}, new WifiP2pManager.DnsSdTxtRecordListener() {
#Override
public void onDnsSdTxtRecordAvailable(
String fullDomainName, Map<String, String> record,
WifiP2pDevice device) {
// do all the things you need to do with detailed information about detected service
}
});
mWifiP2pServiceRequest = WifiP2pDnsSdServiceRequest.newInstance();
}
private void startServiceDiscovery() {
mWifiP2pManager.removeServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
mWifiP2pManager.addServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
mWifiP2pManager.discoverServices(mWifiP2pChannel,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
//service discovery started
mServiceDiscoveringHandler.postDelayed(
mServiceDiscoveringRunnable,
SERVICE_DISCOVERING_INTERVAL);
}
#Override
public void onFailure(int error) {
// react to failure of starting service discovery
}
});
}
#Override
public void onFailure(int error) {
// react to failure of adding service request
}
});
}
#Override
public void onFailure(int reason) {
// react to failure of removing service request
}
});
}
the mServiceDiscoveringRunnable was just:
private Runnable mServiceDiscoveringRunnable = new Runnable() {
#Override
public void run() {
startServiceDiscovery();
}
};
All this made my system work quite well. It wasn't perfect yet, but with the lack of documentation on this subject I think I couldn't do much more to improve it.
If you test this approach, be sure to tell me how it works for you (or if it works for you ;) ).
if the problem is the detection of the service i believe that crearing group is the best way to make the device and service detectable but the if created group in the all devices then you cannot connect in direct.
but as wifi network.
i do it every day and it works.
This is in my layout :
<android.support.v7.app.MediaRouteButton
android:id="#+id/button_fling"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:background="#drawable/mr_ic_media_route_holo_light"
android:layout_height="wrap_content"
android:mediaRouteTypes="user"
android:layout_weight="1"
android:visibility="visible" />
and this in my my activity:
#Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mMediaRouteSelector = new MediaRouteSelector.Builder()
.addControlCategory(CastMediaControlIntent.categoryForCast(getString(R.string.app_id)))
.build();
mMediaRouterCallback = new MyMediaRouterCallback();
mMediaRouteButton = (MediaRouteButton) findViewById(R.id.button_fling);
mMediaRouteButton.setRouteSelector(mMediaRouteSelector);
button_fling2 = (ImageView)findViewById(R.id.button_fling2);
}
public class MyMediaRouterCallback extends MediaRouter.Callback {
public int mRouteCount =0;
#Override
public void onRouteAdded(MediaRouter router, RouteInfo route) {
Log.d(TAG, "onRouteAdded");
if (++mRouteCount == 1) {
// Show the button when a device is discovered.
Log.i(TAG,"MediaRoute is visible");
button_fling2.setVisibility(View.VISIBLE);
mMediaRouteButton.setVisibility(View.VISIBLE);
}
}
#Override
public void onRouteRemoved(MediaRouter router, RouteInfo route) {
Log.d(TAG, "onRouteRemoved");
if (--mRouteCount == 0) {
// Hide the button if there are no devices discovered.
Log.i(TAG,"MediaRoute is GONE");
button_fling2.setVisibility(View.GONE);
mMediaRouteButton.setVisibility(View.GONE);
}
}
}
ButtonFling2 is an ImageView I am using to test MyMediaRouterCallback is working or not. It successfully hides/shows the imageView. However for button_fling(which is a mediaRouteButton instance) does not show anything. It's as if it can't find the resources of the MediaRouteButton so it is showing no cast icon... anyone ever fix this or come across this?
I don't get any errors it just simply does not show, but the logs show that it is visible and the ImageView i have for testing shows up.
AFter fiddling around with this thing, I was able to get the media Router button to show up. I am not entirely sure what I did but I did verify the appid and tried to use my whitelisted app id. I reinstalled the support library. THANK YOU ALL FOR WHO HELPED ON THIS!
I am not 100% sure how this happened but I hope that this helps someone figure out or at least get past this. ActionBar Activity and non action bar activities show the media router button now!!! :)
Implementing onRouteChanged() callback instead of onRouteAdded() should fix the issue.
Example code:
// for MediaRouterButtonActivity
#Override
public void onRouteChanged(MediaRouter router, RouteInfo route) {
if (++mRouteCount == 1) {
// Show the button when a device is discovered.
mMediaRouteButton.setVisibility(View.VISIBLE);
}
}
As in the title I've been able to connect to Google Game Services, exchange data between two devices and everything is running fine, except one thing: disconnection callbacks.
I tried to intercept both onPeersDisconnected and onP2PDisconnected without any success. The onP2PDisconnected method is being called in the device that get disconnected from Internet but not into device that is still online (so there is no way to tell the player that the other one got disconnected).
After the match is started it seems that the second device is never notified of the accidental disconnection. If the user close the game properly the onPeersLeft method is being called thought.
Is a ping between the two devices really necessary to overcome this "bug"? Am I doing something wrong?
Here is the code I use:
void startQuickGame() {
// quick-start a game with 1 randomly selected opponent
final int MIN_OPPONENTS = 1, MAX_OPPONENTS = 1;
Bundle autoMatchCriteria = RoomConfig.createAutoMatchCriteria(MIN_OPPONENTS,
MAX_OPPONENTS, 0);
RoomConfig.Builder rtmConfigBuilder = RoomConfig.builder(this);
rtmConfigBuilder.setMessageReceivedListener(this);
rtmConfigBuilder.setRoomStatusUpdateListener(this);
rtmConfigBuilder.setAutoMatchCriteria(autoMatchCriteria);
mListener.switchToScreen(R.id.screen_wait);
keepScreenOn();
resetGameVars();
getGamesClient().createRoom(rtmConfigBuilder.build());
}
And here the simple listeners:
#Override
public void onPeersDisconnected(Room room, List<String> peers) {
Log.d(TAG, "onPeersDisconnected");
updateRoom(room);
}
void updateRoom(Room room) {
Log.d(TAG, "UpdateRoom: "+room.getParticipants().size());
mParticipants = room.getParticipants();
}
#Override
public void onP2PDisconnected(String participantId) {
Log.d(TAG, "onP2PDisconnected");
}
public int getPartecipantsInRooom(){
if(mRoom != null)
return mRoom.getParticipants().size();
else
return -123456;
}
Note that calling getPartecipantsInRooom() after one of the two devices disconnects always return 2, and updateRoom never get called.
Just to be sure this might not work for you, for my applications I use this to let me know when another Participant has left the Room, and it is called immediately :
#Override
public void onPeerLeft(Room room, final List<String> participantIds) {
this.mRoomCurrent = room;
this.mRoomId = this.mRoomCurrent.getRoomId();
this.mParticipants = this.mRoomCurrent.getParticipants();
int connected = 0;
for (Participant p : room.getParticipants()) {
if(p.getStatus() == Participant.STATUS_JOINED) {
connected += 1;
}
}
final int fconnected = connected;
for (String s : listIgnoreTheseIDs) {
//checkint to see if we care anymore about this ID.. if out of game already.. nope
if(s.equals(participantIds.get(0))){
return;
}
}
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
mGHInterface.onPeerLeft(fconnected, participantIds.size());
}
});
}
No idea why there are two items, but like you, I realized the onPeersDisconnected() isn't that reliable, but onPeerLeft() normally gets back to the other devices in under 1 second.
onPeerDisconnected() handles disconnects. So if somebody is still in the application but the network connection is lost, this is called for him.
onPeerLeft() handles participants who leave a room. This is called when somebody explizit leaves the room in the application or the application is minimized, and the room is left on the androids onStop() or onDestroy() callback.
I'm making two player game. So I use this approach
#Override
public void onPeerLeft(Room room, List<String> peersWhoLeft) {
updateRoom(room);
Toast.makeText(MyLauncherActivity.this, "Other player left the game", Toast.LENGTH_LONG).show();
quitGame();
}
I'm pretty new with Android programming. But I have been working on this for over a week now, and it starts to get booooring.
My idea is that I want to connect two devices using Wifi Direct. But I only want to connect to those which are running my application. Besides, I want the users to be able to see some information of the other devices (such as user name), not just the MAC or the Android_XXXX name included in the WifiP2pDevice. That's why I decided that a device looking for other devices, should both start the application service and search for peers which are also broadcasting this service.
The problem (I'm testing with two real devices) is that, even though they are running exactly the same code, only one of them is getting the service discovery callbacks (the onDnsSd... listeners below). So, one side acts in the proper way, but not the other. Moreover I'm getting "old" services, meaning that apparently each time I start de service (even though I cancel previously started services), that service seems to be still broadcast during at least some minutes.
I include a shortened version of my code:
public class MoveFlufietsDialogFragment extends DialogFragment implements ChannelListener, DeviceActionListener {
public final HashMap<String, FlufietsPeer> mBuddies = new HashMap<String, FlufietsPeer>();
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
...
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) getActivity().getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(getActivity(), getActivity().getMainLooper(), null);
...
startRegistration();
discoverFlufietsService();
...
}
public void discoverFlufietsService() {
DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
#Override
public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
// This and the next listener are only called in one of the devices.
String serviceName = (String) record.get("serviceName");
if ((serviceName != null) && (serviceName.equals("flufiets")) {
// I put the record data in the mBuddies HashMap.
...
mBuddies.put(device.deviceAddress, myPeerDataStructure);
}
}
};
DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) {
if (mBuddies.containsKey(resourceType.deviceAddress)) {
FlufietsPeer flufietsPeer = mBuddies.get(resourceType.deviceAddress);
WiFiPeerListAdapter adapter = ((WiFiPeerListAdapter) mFragmentList.getListAdapter());
adapter.add(flufietsPeer);
adapter.notifyDataSetChanged();
}
}
};
mManager.setDnsSdResponseListeners(mChannel, servListener, txtListener);
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
mManager.addServiceRequest(mChannel, serviceRequest, new ActionListener() {
// onSuccess/onFailure toasts.
});
mManager.discoverServices(mChannel, new WifiP2pManager.ActionListener() {
// onSuccess/onFailure toasts.
});
}
public void startRegistration() {
mManager.clearLocalServices(mChannel, new ActionListener() {
// onSuccess/onFailure toasts.
});
Map record = new HashMap();
record.put("serviceName", "flufiets");
...
WifiP2pDnsSdServiceInfo serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(flufietsService, "_tcp", record);
mManager.addLocalService(mChannel, serviceInfo, new ActionListener() {
// onSuccess/onFailure toasts.
});
}
#Override
public void onResume() {
super.onResume();
mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
getActivity().registerReceiver(mReceiver, mIntentFilter);
}
#Override
public void onPause() {
super.onPause();
getActivity().unregisterReceiver(mReceiver);
}
#Override
public void onStop() {
super.onStop();
mManager.clearLocalServices(mChannel, new ActionListener() {
// onSuccess/onFailure toasts.
});
}
...
}
The problem doesn't seem to be related with the device itself (sometimes it works, sometimes it doesn't, but always only in one of them). I suspect it has to do with either trying to discover a service that we ourselves are broadcasting, or having the same service being offered by two devices. I have tried changing the names of the service, so each device would offer either a "send" or "receive" service, but it doesn't work. I only get the callbacks called (onDnsSd...) in one of the devices.
And that thing about getting old services, when I always clear them, is weird (I do include a timestamp in the service record data, and I could always discard all but the last, but doesn't seem to be logical).
Any ideas? ANY help would be VERY appreciated, because writing the application is not funny any more (:-)=
Thanks a lot!
You need to wait until the clearLocalService call succeeds before adding the local service later. So put the addLocalService call into the onSuccess callback of the clearLocalServices.
I know that Wifi Direct works by creating a Soft AP (software access point) in one of the devices. I also know that many Androids support Wifi Direct, but iPhones do not.
My question is: is it possible to create a device-to-device wifi link that is Wifi Direct on the Android side, but regular wifi on the iPhone side? Where the Android's Wifi Direct would be presenting a soft AP, which the iPhone would see as indistinguishable from a regular AP and be able to associate to.
Imagine that this is out in the wilderness where no router AP is available. Also, neither user has a tethering plan.
This link would be used by a Bump-like app to transfer files.
Depending on your phone you can just set up your Android phone as a portable hotspot and connect to that with the iPhone. From there it would be application specific to get data transferred.
However you can also use the Androids WiFi-Direct libraries. In that case you would use them to set up the Android phone to create a "Group owner", which basically is the same as it being a portable hotspot. Check out:
http://developer.android.com/guide/topics/connectivity/wifip2p.html
I'll give you a code example to help you get started.
public class WifiDirectAPtestActivity extends Activity
{
private WifiP2pManager manager;
private boolean isWifiP2pEnabled = false;
private boolean retryChannel = false;
private final IntentFilter intentFilter = new IntentFilter();
private Channel channel;
private BroadcastReceiver receiver = null;
public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled) {
this.isWifiP2pEnabled = isWifiP2pEnabled;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// add necessary intent values to be matched.
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);
}
/** register the BroadcastReceiver with the intent values to be matched */
#Override
public void onResume() {
super.onResume();
receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
registerReceiver(receiver, intentFilter);
createGroup();
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(receiver);
manager.removeGroup(channel, new ActionListener() {
#Override
public void onFailure(int reasonCode) {
Log.d("WifiDirectAptestActivity", "Disconnect failed. Reason :" + reasonCode);
}
#Override
public void onSuccess() {
Log.d("WifiDirectAptestActivity", "Should have been sucessfully removed");
}
});
}
public void createGroup()
{
manager.createGroup(channel, new ActionListener() {
#Override
public void onSuccess() {
// WiFiDirectBroadcastReceiver will notify us. Ignore for now.
Log.d("WifiDirectAPtestActivity", "Group creating request successfully send");
}
#Override
public void onFailure(int reason) {
Toast.makeText(WifiDirectAPtestActivity.this, "Connect failed. Retry.",
Toast.LENGTH_SHORT).show();
}
});
}
In addition you'll need the broadcast receiver, look at the WiFi-Direct demo and it should be clear to you.
Note that line manager.createGroup(channel, new ActionListener() is the codeline of interest, it is this line that actually sets up the device as a portable hotspot.
Hope this clarifies things, I don't really know how detailed explanation you need. Comment if some things are not clear.