Wi-Fi Direct Android - android

I want to transfer files between 2 devices via Wi-Fi Direct.
I wanted to do the same thing as in WifiDirectDemo, but I can't transfer data from the group owner to the other device, so I tried this: each time when one of the devices clicks connect, the other device is set as the group owner, so on each connection the device who asks for connection is always the client and can send data.
The problem with this is that Android always remembers the first group created and therefore its group owner. In other words, what I did only works the first time unless I go to settings and forget the group created by the first connection.
I know that by using the disconnect button, the Wi-Fi group is removed, but the Android system puts it in remembered groups and uses its setting (group owner negotiation) when a new connection is to be made.
The second thing I tried was to create a ServerSocket on each device (on another port), so this way both the group owner and the other device would be clients and servers at the same time. I don't know if the group owner can be set as a client, but I cant create a ServerSocket on both devices. Here is my code:
<pre>
#Override
public void onConnectionInfoAvailable(final WifiP2pInfo info) {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
this.info = info;
this.getView().setVisibility(View.VISIBLE);
// The owner IP is now known.
TextView view = (TextView) mContentView.findViewById(R.id.group_owner);
view.setText( getResources().getString(R.string.group_owner_text)
+ ((info.isGroupOwner == true) ? getResources().getString(R.string.yes)
: getResources().getString(R.string.no)));
// InetAddress from WifiP2pInfo struct.
view = (TextView) mContentView.findViewById(R.id.device_info);
view.setText("Group Owner IP - " + info.groupOwnerAddress.getHostAddress());
// After the group negotiation, we assign the group owner as the file
// server. The file server is single threaded, single connection server
// socket.
if (info.groupFormed && info.isGroupOwner) {
new FileServerAsyncTask(getActivity(), mContentView.findViewById(R.id.status_text),8988)
.execute();
mContentView.findViewById(R.id.btn_start_client).setVisibility(View.VISIBLE);
Log.d(WiFiDirectActivity.TAG, "serveur8988cree");
} else if (info.groupFormed) {
// The other device acts as the client. In this case, we enable the
// Get file button.
// In this case we create a server socket on another port
new FileServerAsyncTask(getActivity(), mContentView.findViewById(R.id.status_text),8987)
.execute();
mContentView.findViewById(R.id.btn_start_client).setVisibility(View.VISIBLE);
Log.d(WiFiDirectActivity.TAG, "serveur8987cree");
((TextView) mContentView.findViewById(R.id.status_text)).setText(getResources()
.getString(R.string.client_text));
}
</pre>
Thanks for help.

You can delete all groups through reflection but, it's bit of a hack and class members might change later
private void deletePersistentInfo() {
try {
Class persistentInterface = null;
//Iterate and get class PersistentGroupInfoListener
for (Class<?> classR : WifiP2pManager.class.getDeclaredClasses()) {
if (classR.getName().contains("PersistentGroupInfoListener")) {
persistentInterface = classR;
break;
}
}
final Method deletePersistentGroupMethod = WifiP2pManager.class.getDeclaredMethod("deletePersistentGroup", new Class[]{Channel.class, int.class, ActionListener.class});
//anonymous class to implement PersistentGroupInfoListener which has a method, onPersistentGroupInfoAvailable
Object persitentInterfaceObject =
java.lang.reflect.Proxy.newProxyInstance(persistentInterface.getClassLoader(),
new java.lang.Class[]{persistentInterface},
new java.lang.reflect.InvocationHandler() {
#Override
public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws java.lang.Throwable {
String method_name = method.getName();
if (method_name.equals("onPersistentGroupInfoAvailable")) {
Class wifiP2pGroupListClass = Class.forName("android.net.wifi.p2p.WifiP2pGroupList");
Object wifiP2pGroupListObject = wifiP2pGroupListClass.cast(args[0]);
Collection<WifiP2pGroup> wifiP2pGroupList = (Collection<WifiP2pGroup>) wifiP2pGroupListClass.getMethod("getGroupList", null).invoke(wifiP2pGroupListObject, null);
for (WifiP2pGroup group : wifiP2pGroupList) {
deletePersistentGroupMethod.invoke(wifiP2pManager, channel, (Integer) WifiP2pGroup.class.getMethod("getNetworkId").invoke(group, null), new ActionListener() {
#Override
public void onSuccess() {
//All groups deleted
}
#Override
public void onFailure(int i) {
}
});
}
}
return null;
}
});
Method requestPersistentGroupMethod =
WifiP2pManager.class.getDeclaredMethod("requestPersistentGroupInfo", new Class[]{Channel.class, persistentInterface});
requestPersistentGroupMethod.invoke(wifiP2pManager, channel, persitentInterfaceObject);
} catch (Exception ex) {
ex.printStackTrace();
}
}

To send data you need to know the IP address (not the device address) of the receiver. For the P2P client, the IP address of group_owner is available in the WifiP2pInfo variable, so it can use this to send data to the group owner. If the group owner knows the IP address of the P2P client to which it wants to send data, then it can also send files. This can be achieved in two ways.
Group owner assigns the IP addresses to the clients and stores the information about it.
Every newly added client sends its IP address to the group owner at the time of joining the group.

Related

Create MUC group like whatsapp Android

I can creating and joining MUC rooms. But user disconnects from the Openfire server, he is removed from the group on the server side. How can i similar to what Whatsapp does, i.e. even if the user goes offline, he is still part of the MUC room (which is configured to be persistent on the server side) and will receive messages from other occupants.
When inviting an user, you have to grant him Membership:
MultiUserChat muc = multiUserChatManager.getMultiUserChat("foo#conference.myserver");
muc.invite("jhondoe#myserver","Join this groupchat!");
then you can grant him voice and you must grantMembership (or Ownership or Moderation as you like/need):
muc.grantVoice("jhondoe#myserver");
muc.grantMembership("jhondoe#myserver");
finally you have to integrate a list like that with your client:
public List<String> retriveAllAffialiateOfMuc(MultiUserChat muc) throws NoResponseException, XMPPErrorException, NotConnectedException
{
List<Affiliate> affiliatesMembers = new ArrayList<Affiliate>();
if (muc.getAdmins() != null)
{
affiliatesMembers.addAll( muc.getAdmins() );
}
if ( muc.getMembers() != null)
{
affiliatesMembers.addAll( muc.getMembers() );
}
if ( muc.getOwners() != null )
{
affiliatesMembers.addAll( muc.getOwners() );
}
if (affiliatesMembers.size() == 0)
{
System.out.println("Error: looking for a non existant room");
return new ArrayList<String>(0);
}
List<String> affiliateMembersNames = new ArrayList<String>(affiliatesMembers.size());
for (Affiliate affiliate : affiliatesMembers)
{
affiliateMembersNames.add(affiliate.getJid().toString());
}
return affiliateMembersNames;
}
So you'll have a list of all users affiliate to the room.
You can use this list in some callback to make a list of "all members" like in WhatsApp.
Look at the end of this page:
https://www.igniterealtime.org/builds/smack/dailybuilds/documentation/extensions/muc.html
(dont' forget to vote!)

How to add users to a roster in xmpp?

I have successfully created a user using the following code:
accountmanager = new org.jivesoftware.smack.AccountManager(connection);
accountmanager.createAccount(fbuserid,fbuserid);
But I am not able to add other users to the logged in user's roster using the following code :
public void createEntry(String user, String name, String[] groups) throws XMPPException {
// Create and send roster entry creation packet.
RosterPacket rosterPacket = new RosterPacket();
rosterPacket.setType(IQ.Type.SET);
RosterPacket.Item item = new RosterPacket.Item(user, name);
if (groups != null) {
for (String group : groups) {
if (group != null) {
item.addGroupName(group);
}
}
}
rosterPacket.addRosterItem(item);
// Wait up to a certain number of seconds for a reply from the server.
PacketCollector collector = connection.createPacketCollector(
new PacketIDFilter(rosterPacket.getPacketID()));
connection.sendPacket(rosterPacket);
IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
collector.cancel();
if (response == null) {
throw new XMPPException("No response from the server.");
}
// If the server replied with an error, throw an exception.
else if (response.getType() == IQ.Type.ERROR) {
throw new XMPPException(response.getError());
}
// Create a presence subscription packet and send.
Presence presencePacket = new Presence(Presence.Type.subscribe);
presencePacket.setTo(user);
connection.sendPacket(presencePacket);
}
I am always getting the response as null. Someone please help me to solve this and Thanks in advance
Rosters and presence use a permissions-based model where users must give permission before they are added to someone else's roster. This protects a user's privacy by making sure that only approved users are able to view their presence information. Therefore, when you add a new roster entry it will be in a pending state until the other user accepts your request.
If another user requests a presence subscription so they can add you to their roster, you must accept or reject that request. Smack handles presence subscription requests in one of three ways:
Automatically accept all presence subscription requests.
Automatically reject all presence subscription requests.
Process presence subscription requests manually. The mode can be set using the
Roster.setSubscriptionMode(Roster.SubscriptionMode) method. Simple clients normally use one of the automated subscription modes, while full-featured clients should manually process subscription requests and let the end-user accept or reject each request. If using the manual mode, a PacketListener should be registered that listens for Presence packets that have a type of Presence.Type.subscribe.
Try this in code first to add user in roster as well as requesting the users permission.
roster = Roster.getInstanceFor(connection);
if (!roster.isLoaded())
try {
roster.reloadAndWait();
} catch (SmackException.NotLoggedInException e) {
Log.i(TAG, "NotLoggedInException");
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
Log.i(TAG, "NotConnectedException");
e.printStackTrace();
}
roster.createEntry(jID, name, null);
On other user side/ in your code after login from one user:
roster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
To make user status online:
Presence presence = new Presence(Presence.Type.available);
presence.setStatus("Online, Programmatically!");
presence.setPriority(24);
presence.setMode(Presence.Mode.available);
roster = Roster.getInstanceFor(connection);

Android Wear + Wearable ChannelApi + How to open connection to cloud node (WIFI)?

The connection via bluetooth using the new Channel API is working like it should, but if I now switch to the cloud node (WIFI mode) the channel can't be opened. The result is always null and running into a timeout.
ChannelApi.OpenChannelResult result = Wearable.ChannelApi.openChannel(googleApiClient, "cloud", Constants.COPY_FILE_VIA_CHANNEL_PATH).await();
Is this the right way to establish a WIFI connection between nodes and is there somewhere an example how to implement this?
update:
on watch:
(afterwards send nodeID to phone via message. I used this approach after also seeing the problems from this thread Android Wear + Wearable ChannelApi openChannel not opening with remote node?)
on watch: (Send retrieved localNodeID to phone)
NodeApi.GetLocalNodeResult localNodeResult = Wearable.NodeApi.getLocalNode(googleApiClient).await();
on phone:
ChannelApi.OpenChannelResult result = Wearable.ChannelApi.openChannel(googleApiClient, localNodeId, Constants.COPY_FILE_VIA_CHANNEL_PATH).await();
Channel.GetOutputStreamResult getOutputStreamResult = channel.getOutputStream(googleApiClient).await();
OutputStream outputStream = getOutputStreamResult.getOutputStream();
outputStream.write(byteChunk);
outputStream.close();
on watch:
#Override
public void onChannelOpened(Channel channel) {
if (channel.getPath()
.equals(Constants.COPY_FILE_VIA_CHANNEL_PATH)) {
new SaveDataFromChannelTask(channel).execute();
}
}
protected class SaveDataFromChannelTask extends AsyncTask<Void, Void, Void> {
private final Channel channel;
public SaveDataFromChannelTask(Channel channel) {
this.channel = channel;
}
#Override
protected Void doInBackground(Void... params) {
Channel.GetInputStreamResult getInputStreamResult = channel.getInputStream(googleApiClient)
.await();
InputStream inputStream = getInputStreamResult.getInputStream();
saveFileToDisk(inputStream);
return null;
}
}
This is currently the implementation inside the "Wear Media" app, which is using the Channel API. Inside the settings the chunksize can be modified to any byte value between 1000 and 9999999, but during transfer and activated bluetooth and WIFI always the bluetooth connection is used.
"cloud" is not a valid node id - you need to use a node id of a device such as a phone or Android Wear device. The devices will automatically switch from bluetooth to wifi based on the underlying connection - there is nothing you need to do. You can use the CapabilityApi, similar to the sending messages training, to correctly determine the node id to open a channel with.

How to attach POST variables to socket.io connection?

I have a webchat application which is running on Node.js and Socket.io. After user logins on main homepage port 80, he gets redirected to port 3000 (chat application) along with POST data containing his ID, username etc... On chat application page it validates details and registers user as new client.
However, now I am building android chat application and I get immediately disconnected from chat because basically android client fails validation since there is no POST data attached.
How can I add POST data along with connection request?
Here is a code that does it all in android:
try {
IO.Options opts = new IO.Options();
opts.forceNew = true;
final Socket socket = IO.socket("http://host:3000", opts);
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener(){
#Override
public void call(Object... args){
socket.emit("mobile_ping", sf.getTextValue(MainActivity.this, R.id.editText));
}
});
socket.connect();
} catch (Exception e) {
Log.d("ERR", String.valueOf(e));
}

Android ADD FRIEND using Smack

I am new to the use of smack library and making one chatting application. I have made upto much extent and at this step i want to ask two questions.
when i add a friend the friend got added in my list but there is not any notification sent to the FRIEND whom i have added, How to achieve the same. I have added the code below.
The second thing i want to ask is that how can I check whether the user which I am going to add is a part or member of the app or not ( mean it is on the server or not). So that the user who is not registered to the app should not be added in the friends list.
here is the code
public static boolean addFriend(String jid) {
String nickname = null;
nickname = StringUtils.parseBareAddress(jid);
RosterEntry entry4 = roster.getEntry("samsad");
if (!roster.contains(jid)) {
try {
Presence subscribe = new Presence(Presence.Type.subscribe);
subscribe.setTo(jid);
connection.sendPacket(subscribe);
roster.createEntry(jid, nickname, null);
// Send a roster entry (any) to user2
RosterExchangeManager REM = new RosterExchangeManager(connection);
REM.send(entry4, jid);
return true;
} catch (XMPPException e) {
System.err.println("Error in adding friend");
return false;
}
} else {
return false;
}
}
Roster Exchange manager running in the service in background
/**Remotr Exchange Manager*/
RosterExchangeManager rem = new RosterExchangeManager(connection);
// Create a RosterExchangeListener that will iterate over the received roster entries
RosterExchangeListener rosterExchangeListener = new RosterExchangeListener() {
public void entriesReceived(String from, Iterator remoteRosterEntries) {
notification("Receive==4");
while (remoteRosterEntries.hasNext()) {
try {
// Get the received entry
RemoteRosterEntry remoteRosterEntry = (RemoteRosterEntry) remoteRosterEntries.next();
// Display the remote entry on the console
System.out.println(remoteRosterEntry);
// Add the entry to the user2's roster
roster.createEntry(
remoteRosterEntry.getUser(),
remoteRosterEntry.getName(),
remoteRosterEntry.getGroupArrayNames());
notification("Receive==1");
}
catch (XMPPException e) {
e.printStackTrace();
}
}
}
};
rem.addRosterListener(rosterExchangeListener);
}
else{
showToast("Connection lost-",0);
}
}
1, The problem is you must register a PacketListener for Presence.Type.subscribe before you connect to server. All the process of add and accept friend i answered in here
2, You can use UserSearch class to search for a specific user and if user is not found on server then you can assume that user is not registered on server.

Categories

Resources