am 67ea8c86
: Merge "Added a persistent feature in WiFi Direct."
* commit '67ea8c86419ffbf603052e816d6b1e9e7e20fbb9': Added a persistent feature in WiFi Direct.
This commit is contained in:
@ -20,6 +20,8 @@ import android.net.NetworkInfo;
|
||||
import android.net.wifi.p2p.WifiP2pConfig;
|
||||
import android.net.wifi.p2p.WifiP2pDevice;
|
||||
import android.net.wifi.p2p.WifiP2pGroup;
|
||||
import android.net.wifi.p2p.WifiP2pService;
|
||||
import android.net.wifi.p2p.WifiP2pService.P2pStatus;
|
||||
import android.net.wifi.p2p.WifiP2pProvDiscEvent;
|
||||
import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
|
||||
import android.net.wifi.StateChangeResult;
|
||||
@ -186,7 +188,7 @@ public class WifiMonitor {
|
||||
|
||||
/* P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437
|
||||
[psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|passphrase="fKG4jMe3"]
|
||||
go_dev_addr=fa:7b:7a:42:02:13 */
|
||||
go_dev_addr=fa:7b:7a:42:02:13 [PERSISTENT] */
|
||||
private static final String P2P_GROUP_STARTED_STR = "P2P-GROUP-STARTED";
|
||||
|
||||
/* P2P-GROUP-REMOVED p2p-wlan0-0 [client|GO] reason=REQUESTED */
|
||||
@ -594,7 +596,13 @@ public class WifiMonitor {
|
||||
if (tokens.length != 2) return;
|
||||
String[] nameValue = tokens[1].split("=");
|
||||
if (nameValue.length != 2) return;
|
||||
mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, nameValue[1]);
|
||||
P2pStatus err = P2pStatus.UNKNOWN;
|
||||
try {
|
||||
err = P2pStatus.valueOf(Integer.parseInt(nameValue[1]));
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, err);
|
||||
} else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) {
|
||||
mStateMachine.sendMessage(P2P_PROV_DISC_PBC_REQ_EVENT,
|
||||
new WifiP2pProvDiscEvent(dataString));
|
||||
|
@ -547,10 +547,9 @@ public class WifiNative {
|
||||
break;
|
||||
}
|
||||
|
||||
//TODO: Add persist behavior once the supplicant interaction is fixed for both
|
||||
// group and client scenarios
|
||||
/* Persist unless there is an explicit request to not do so*/
|
||||
//if (config.persist != WifiP2pConfig.Persist.NO) args.add("persistent");
|
||||
if (config.netId == WifiP2pGroup.PERSISTENT_NET_ID) {
|
||||
args.add("persistent");
|
||||
}
|
||||
|
||||
if (joinExistingGroup) {
|
||||
args.add("join");
|
||||
@ -592,10 +591,17 @@ public class WifiNative {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean p2pGroupAdd() {
|
||||
public boolean p2pGroupAdd(boolean persistent) {
|
||||
if (persistent) {
|
||||
return doBooleanCommand("P2P_GROUP_ADD persistent");
|
||||
}
|
||||
return doBooleanCommand("P2P_GROUP_ADD");
|
||||
}
|
||||
|
||||
public boolean p2pGroupAdd(int netId) {
|
||||
return doBooleanCommand("P2P_GROUP_ADD persistent=" + netId);
|
||||
}
|
||||
|
||||
public boolean p2pGroupRemove(String iface) {
|
||||
if (TextUtils.isEmpty(iface)) return false;
|
||||
return doBooleanCommand("P2P_GROUP_REMOVE " + iface);
|
||||
@ -624,6 +630,9 @@ public class WifiNative {
|
||||
return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress);
|
||||
}
|
||||
|
||||
public String p2pGetSsid(String deviceAddress) {
|
||||
return p2pGetParam(deviceAddress, "oper_ssid");
|
||||
}
|
||||
|
||||
public String p2pGetDeviceAddress() {
|
||||
String status = status();
|
||||
@ -665,6 +674,24 @@ public class WifiNative {
|
||||
return doStringCommand("P2P_PEER " + deviceAddress);
|
||||
}
|
||||
|
||||
private String p2pGetParam(String deviceAddress, String key) {
|
||||
if (deviceAddress == null) return null;
|
||||
|
||||
String peerInfo = p2pPeer(deviceAddress);
|
||||
if (peerInfo == null) return null;
|
||||
String[] tokens= peerInfo.split("\n");
|
||||
|
||||
key += "=";
|
||||
for (String token : tokens) {
|
||||
if (token.startsWith(key)) {
|
||||
String[] nameValue = token.split("=");
|
||||
if (nameValue.length != 2) break;
|
||||
return nameValue[1];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean p2pServiceAdd(WifiP2pServiceInfo servInfo) {
|
||||
/*
|
||||
* P2P_SERVICE_ADD bonjour <query hexdump> <RDATA hexdump>
|
||||
|
@ -46,18 +46,8 @@ public class WifiP2pConfig implements Parcelable {
|
||||
*/
|
||||
public int groupOwnerIntent = -1;
|
||||
|
||||
/**
|
||||
* Indicates whether the configuration is saved
|
||||
* @hide
|
||||
*/
|
||||
public enum Persist {
|
||||
SYSTEM_DEFAULT,
|
||||
YES,
|
||||
NO
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public Persist persist = Persist.SYSTEM_DEFAULT;
|
||||
public int netId = WifiP2pGroup.PERSISTENT_NET_ID;
|
||||
|
||||
public WifiP2pConfig() {
|
||||
//set defaults
|
||||
@ -110,7 +100,7 @@ public class WifiP2pConfig implements Parcelable {
|
||||
sbuf.append("\n address: ").append(deviceAddress);
|
||||
sbuf.append("\n wps: ").append(wps);
|
||||
sbuf.append("\n groupOwnerIntent: ").append(groupOwnerIntent);
|
||||
sbuf.append("\n persist: ").append(persist.toString());
|
||||
sbuf.append("\n persist: ").append(netId);
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
@ -125,7 +115,7 @@ public class WifiP2pConfig implements Parcelable {
|
||||
deviceAddress = source.deviceAddress;
|
||||
wps = new WpsInfo(source.wps);
|
||||
groupOwnerIntent = source.groupOwnerIntent;
|
||||
persist = source.persist;
|
||||
netId = source.netId;
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,7 +124,7 @@ public class WifiP2pConfig implements Parcelable {
|
||||
dest.writeString(deviceAddress);
|
||||
dest.writeParcelable(wps, flags);
|
||||
dest.writeInt(groupOwnerIntent);
|
||||
dest.writeString(persist.name());
|
||||
dest.writeInt(netId);
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
@ -145,7 +135,7 @@ public class WifiP2pConfig implements Parcelable {
|
||||
config.deviceAddress = in.readString();
|
||||
config.wps = (WpsInfo) in.readParcelable(null);
|
||||
config.groupOwnerIntent = in.readInt();
|
||||
config.persist = Persist.valueOf(in.readString());
|
||||
config.netId = in.readInt();
|
||||
return config;
|
||||
}
|
||||
|
||||
|
@ -231,11 +231,26 @@ public class WifiP2pDevice implements Parcelable {
|
||||
return (deviceCapability & DEVICE_CAPAB_SERVICE_DISCOVERY) != 0;
|
||||
}
|
||||
|
||||
/** Returns true if the device is capable of invitation {@hide}*/
|
||||
public boolean isInvitationCapable() {
|
||||
return (deviceCapability & DEVICE_CAPAB_INVITATION_PROCEDURE) != 0;
|
||||
}
|
||||
|
||||
/** Returns true if the device reaches the limit. {@hide}*/
|
||||
public boolean isDeviceLimit() {
|
||||
return (deviceCapability & DEVICE_CAPAB_DEVICE_LIMIT) != 0;
|
||||
}
|
||||
|
||||
/** Returns true if the device is a group owner */
|
||||
public boolean isGroupOwner() {
|
||||
return (groupCapability & GROUP_CAPAB_GROUP_OWNER) != 0;
|
||||
}
|
||||
|
||||
/** Returns true if the group reaches the limit. {@hide}*/
|
||||
public boolean isGroupLimit() {
|
||||
return (groupCapability & GROUP_CAPAB_GROUP_LIMIT) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
|
@ -33,6 +33,16 @@ import java.util.regex.Matcher;
|
||||
*/
|
||||
public class WifiP2pGroup implements Parcelable {
|
||||
|
||||
/** The temporary network id.
|
||||
* {@hide} */
|
||||
public static final int TEMPORARY_NET_ID = -1;
|
||||
|
||||
/** The persistent network id.
|
||||
* If a matching persistent profile is found, use it.
|
||||
* Otherwise, create a new persistent profile.
|
||||
* {@hide} */
|
||||
public static final int PERSISTENT_NET_ID = -2;
|
||||
|
||||
/** The network name */
|
||||
private String mNetworkName;
|
||||
|
||||
@ -50,13 +60,17 @@ public class WifiP2pGroup implements Parcelable {
|
||||
|
||||
private String mInterface;
|
||||
|
||||
/** The network id in the wpa_supplicant */
|
||||
private int mNetId;
|
||||
|
||||
/** P2P group started string pattern */
|
||||
private static final Pattern groupStartedPattern = Pattern.compile(
|
||||
"ssid=\"(.+)\" " +
|
||||
"freq=(\\d+) " +
|
||||
"(?:psk=)?([0-9a-fA-F]{64})?" +
|
||||
"(?:passphrase=)?(?:\"(.{8,63})\")? " +
|
||||
"go_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2})"
|
||||
"go_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2})" +
|
||||
" ?(\\[PERSISTENT\\])?"
|
||||
);
|
||||
|
||||
public WifiP2pGroup() {
|
||||
@ -67,13 +81,15 @@ public class WifiP2pGroup implements Parcelable {
|
||||
*
|
||||
* P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437
|
||||
* [psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|
|
||||
* passphrase="fKG4jMe3"] go_dev_addr=fa:7b:7a:42:02:13
|
||||
* passphrase="fKG4jMe3"] go_dev_addr=fa:7b:7a:42:02:13 [PERSISTENT]
|
||||
*
|
||||
* P2P-GROUP-REMOVED p2p-wlan0-0 [client|GO] reason=REQUESTED
|
||||
*
|
||||
* P2P-INVITATION-RECEIVED sa=fa:7b:7a:42:02:13 go_dev_addr=f8:7b:7a:42:02:13
|
||||
* bssid=fa:7b:7a:42:82:13 unknown-network
|
||||
*
|
||||
* P2P-INVITATION-RECEIVED sa=b8:f9:34:2a:c7:9d persistent=0
|
||||
*
|
||||
* Note: The events formats can be looked up in the wpa_supplicant code
|
||||
* @hide
|
||||
*/
|
||||
@ -100,16 +116,38 @@ public class WifiP2pGroup implements Parcelable {
|
||||
//String psk = match.group(3);
|
||||
mPassphrase = match.group(4);
|
||||
mOwner = new WifiP2pDevice(match.group(5));
|
||||
|
||||
if (match.group(6) != null) {
|
||||
mNetId = PERSISTENT_NET_ID;
|
||||
} else {
|
||||
mNetId = TEMPORARY_NET_ID;
|
||||
}
|
||||
} else if (tokens[0].equals("P2P-INVITATION-RECEIVED")) {
|
||||
String sa = null;
|
||||
mNetId = PERSISTENT_NET_ID;
|
||||
for (String token : tokens) {
|
||||
String[] nameValue = token.split("=");
|
||||
if (nameValue.length != 2) continue;
|
||||
|
||||
if (nameValue[0].equals("sa")) {
|
||||
sa = nameValue[1];
|
||||
|
||||
// set source address into the client list.
|
||||
WifiP2pDevice dev = new WifiP2pDevice();
|
||||
dev.deviceAddress = nameValue[1];
|
||||
mClients.add(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nameValue[0].equals("go_dev_addr")) {
|
||||
mOwner = new WifiP2pDevice(nameValue[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nameValue[0].equals("persistent")) {
|
||||
mOwner = new WifiP2pDevice(sa);
|
||||
mNetId = Integer.parseInt(nameValue[1]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Malformed supplicant event");
|
||||
@ -212,6 +250,16 @@ public class WifiP2pGroup implements Parcelable {
|
||||
return mInterface;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getNetworkId() {
|
||||
return mNetId;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setNetworkId(int netId) {
|
||||
this.mNetId = netId;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sbuf = new StringBuffer();
|
||||
sbuf.append("network: ").append(mNetworkName);
|
||||
@ -221,6 +269,7 @@ public class WifiP2pGroup implements Parcelable {
|
||||
sbuf.append("\n Client: ").append(client);
|
||||
}
|
||||
sbuf.append("\n interface: ").append(mInterface);
|
||||
sbuf.append("\n networkId: ").append(mNetId);
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
@ -238,6 +287,7 @@ public class WifiP2pGroup implements Parcelable {
|
||||
for (WifiP2pDevice d : source.getClientList()) mClients.add(d);
|
||||
mPassphrase = source.getPassphrase();
|
||||
mInterface = source.getInterface();
|
||||
mNetId = source.getNetworkId();
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,6 +302,7 @@ public class WifiP2pGroup implements Parcelable {
|
||||
}
|
||||
dest.writeString(mPassphrase);
|
||||
dest.writeString(mInterface);
|
||||
dest.writeInt(mNetId);
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
@ -268,6 +319,7 @@ public class WifiP2pGroup implements Parcelable {
|
||||
}
|
||||
group.setPassphrase(in.readString());
|
||||
group.setInterface(in.readString());
|
||||
group.setNetworkId(in.readInt());
|
||||
return group;
|
||||
}
|
||||
|
||||
|
19
wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl
Normal file
19
wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2012, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.wifi.p2p;
|
||||
|
||||
parcelable WifiP2pGroupList;
|
229
wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
Normal file
229
wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.net.wifi.p2p;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.LruCache;
|
||||
|
||||
|
||||
/**
|
||||
* A class representing a Wi-Fi P2p group list
|
||||
*
|
||||
* {@see WifiP2pManager}
|
||||
* @hide
|
||||
*/
|
||||
public class WifiP2pGroupList implements Parcelable {
|
||||
|
||||
private static final int CREDENTIAL_MAX_NUM = 32;
|
||||
|
||||
private LruCache<Integer, WifiP2pGroup> mGroups;
|
||||
private GroupDeleteListener mListener;
|
||||
private boolean isClearCalled = false;
|
||||
|
||||
public interface GroupDeleteListener {
|
||||
public void onDeleteGroup(int netId);
|
||||
}
|
||||
|
||||
WifiP2pGroupList() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
WifiP2pGroupList(GroupDeleteListener listener) {
|
||||
mListener = listener;
|
||||
mGroups = new LruCache<Integer, WifiP2pGroup>(CREDENTIAL_MAX_NUM) {
|
||||
@Override
|
||||
protected void entryRemoved(boolean evicted, Integer netId,
|
||||
WifiP2pGroup oldValue, WifiP2pGroup newValue) {
|
||||
if (mListener != null && !isClearCalled) {
|
||||
mListener.onDeleteGroup(oldValue.getNetworkId());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of p2p group.
|
||||
*
|
||||
* @return the list of p2p group.
|
||||
*/
|
||||
public Collection<WifiP2pGroup> getGroupList() {
|
||||
return mGroups.snapshot().values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified group to this group list.
|
||||
*
|
||||
* @param group
|
||||
*/
|
||||
void add(WifiP2pGroup group) {
|
||||
mGroups.put(group.getNetworkId(), group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the group with the specified network id from this group list.
|
||||
*
|
||||
* @param netId
|
||||
*/
|
||||
void remove(int netId) {
|
||||
mGroups.remove(netId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the group with the specified device address from this group list.
|
||||
*
|
||||
* @param deviceAddress
|
||||
*/
|
||||
void remove(String deviceAddress) {
|
||||
remove(getNetworkId(deviceAddress));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the group.
|
||||
*/
|
||||
boolean clear() {
|
||||
if (mGroups.size() == 0) return false;
|
||||
isClearCalled = true;
|
||||
mGroups.evictAll();
|
||||
isClearCalled = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the network id of the group owner profile with the specified p2p device
|
||||
* address.
|
||||
* If more than one persistent group of the same address is present in the list,
|
||||
* return the first one.
|
||||
*
|
||||
* @param deviceAddress p2p device address.
|
||||
* @return the network id. if not found, return -1.
|
||||
*/
|
||||
int getNetworkId(String deviceAddress) {
|
||||
if (deviceAddress == null) return -1;
|
||||
|
||||
final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
|
||||
for (WifiP2pGroup grp: groups) {
|
||||
if (deviceAddress.equalsIgnoreCase(grp.getOwner().deviceAddress)) {
|
||||
// update cache ordered.
|
||||
mGroups.get(grp.getNetworkId());
|
||||
return grp.getNetworkId();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the network id of the group with the specified p2p device address
|
||||
* and the ssid.
|
||||
*
|
||||
* @param deviceAddress p2p device address.
|
||||
* @param ssid ssid.
|
||||
* @return the network id. if not found, return -1.
|
||||
*/
|
||||
int getNetworkId(String deviceAddress, String ssid) {
|
||||
if (deviceAddress == null || ssid == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
|
||||
for (WifiP2pGroup grp: groups) {
|
||||
if (deviceAddress.equalsIgnoreCase(grp.getOwner().deviceAddress) &&
|
||||
ssid.equals(grp.getNetworkName())) {
|
||||
// update cache ordered.
|
||||
mGroups.get(grp.getNetworkId());
|
||||
return grp.getNetworkId();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the group owner address of the group with the specified network id
|
||||
*
|
||||
* @param netId network id.
|
||||
* @return the address. if not found, return null.
|
||||
*/
|
||||
String getOwnerAddr(int netId) {
|
||||
WifiP2pGroup grp = mGroups.get(netId);
|
||||
if (grp != null) {
|
||||
return grp.getOwner().deviceAddress;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this group list contains the specified network id.
|
||||
* This function does NOT update LRU information.
|
||||
* It means the internal queue is NOT reordered.
|
||||
*
|
||||
* @param netId network id.
|
||||
* @return true if the specified network id is present in this group list.
|
||||
*/
|
||||
boolean contains(int netId) {
|
||||
final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
|
||||
for (WifiP2pGroup grp: groups) {
|
||||
if (netId == grp.getNetworkId()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sbuf = new StringBuffer();
|
||||
|
||||
final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
|
||||
for (WifiP2pGroup grp: groups) {
|
||||
sbuf.append(grp).append("\n");
|
||||
}
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
|
||||
dest.writeInt(groups.size());
|
||||
for(WifiP2pGroup group : groups) {
|
||||
dest.writeParcelable(group, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public static final Creator<WifiP2pGroupList> CREATOR =
|
||||
new Creator<WifiP2pGroupList>() {
|
||||
public WifiP2pGroupList createFromParcel(Parcel in) {
|
||||
WifiP2pGroupList grpList = new WifiP2pGroupList();
|
||||
|
||||
int deviceCount = in.readInt();
|
||||
for (int i = 0; i < deviceCount; i++) {
|
||||
grpList.add((WifiP2pGroup)in.readParcelable(null));
|
||||
}
|
||||
return grpList;
|
||||
}
|
||||
|
||||
public WifiP2pGroupList[] newArray(int size) {
|
||||
return new WifiP2pGroupList[size];
|
||||
}
|
||||
};
|
||||
}
|
@ -34,10 +34,10 @@ import android.os.IBinder;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.WorkSource;
|
||||
import android.os.Messenger;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.AsyncChannel;
|
||||
@ -266,6 +266,13 @@ public class WifiP2pManager {
|
||||
*/
|
||||
public static final String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
|
||||
|
||||
/**
|
||||
* Broadcast intent action indicating that remembered persistent groups have changed.
|
||||
* @hide
|
||||
*/
|
||||
public static final String WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION =
|
||||
"android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED";
|
||||
|
||||
/**
|
||||
* The lookup key for a {@link #String} object.
|
||||
* Retrieve with {@link android.os.Bundle#getString(String)}.
|
||||
@ -436,6 +443,18 @@ public class WifiP2pManager {
|
||||
/** @hide */
|
||||
public static final int SHOW_PIN_REQUESTED = BASE + 58;
|
||||
|
||||
/** @hide */
|
||||
public static final int DELETE_PERSISTENT_GROUP = BASE + 59;
|
||||
/** @hide */
|
||||
public static final int DELETE_PERSISTENT_GROUP_FAILED = BASE + 60;
|
||||
/** @hide */
|
||||
public static final int DELETE_PERSISTENT_GROUP_SUCCEEDED = BASE + 61;
|
||||
|
||||
/** @hide */
|
||||
public static final int REQUEST_PERSISTENT_GROUP_INFO = BASE + 62;
|
||||
/** @hide */
|
||||
public static final int RESPONSE_PERSISTENT_GROUP_INFO = BASE + 63;
|
||||
|
||||
/**
|
||||
* Create a new WifiP2pManager instance. Applications use
|
||||
* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
|
||||
@ -657,6 +676,15 @@ public class WifiP2pManager {
|
||||
public void onDetached(int reason);
|
||||
}
|
||||
|
||||
/** Interface for callback invocation when stored group info list is available {@hide}*/
|
||||
public interface PersistentGroupInfoListener {
|
||||
/**
|
||||
* The requested stored p2p group info list is available
|
||||
* @param groups Wi-Fi p2p group info list
|
||||
*/
|
||||
public void onPersistentGroupInfoAvailable(WifiP2pGroupList groups);
|
||||
}
|
||||
|
||||
/**
|
||||
* A channel that connects the application to the Wifi p2p framework.
|
||||
* Most p2p operations require a Channel as an argument. An instance of Channel is obtained
|
||||
@ -713,6 +741,7 @@ public class WifiP2pManager {
|
||||
case WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED:
|
||||
case WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED:
|
||||
case WifiP2pManager.SET_DEVICE_NAME_FAILED:
|
||||
case WifiP2pManager.DELETE_PERSISTENT_GROUP_FAILED:
|
||||
if (listener != null) {
|
||||
((ActionListener) listener).onFailure(message.arg1);
|
||||
}
|
||||
@ -732,6 +761,7 @@ public class WifiP2pManager {
|
||||
case WifiP2pManager.REMOVE_SERVICE_REQUEST_SUCCEEDED:
|
||||
case WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED:
|
||||
case WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED:
|
||||
case WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED:
|
||||
if (listener != null) {
|
||||
((ActionListener) listener).onSuccess();
|
||||
}
|
||||
@ -786,6 +816,13 @@ public class WifiP2pManager {
|
||||
mDialogListener = null;
|
||||
}
|
||||
break;
|
||||
case WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO:
|
||||
WifiP2pGroupList groups = (WifiP2pGroupList) message.obj;
|
||||
if (listener != null) {
|
||||
((PersistentGroupInfoListener) listener).
|
||||
onPersistentGroupInfoAvailable(groups);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Ignored " + message);
|
||||
break;
|
||||
@ -995,7 +1032,8 @@ public class WifiP2pManager {
|
||||
*/
|
||||
public void createGroup(Channel c, ActionListener listener) {
|
||||
checkChannel(c);
|
||||
c.mAsyncChannel.sendMessage(CREATE_GROUP, 0, c.putListener(listener));
|
||||
c.mAsyncChannel.sendMessage(CREATE_GROUP, WifiP2pGroup.PERSISTENT_NET_ID,
|
||||
c.putListener(listener));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1296,6 +1334,40 @@ public class WifiP2pManager {
|
||||
c.mAsyncChannel.sendMessage(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a stored persistent group from the system settings.
|
||||
*
|
||||
* <p> The function call immediately returns after sending a persistent group removal request
|
||||
* to the framework. The application is notified of a success or failure to initiate
|
||||
* group removal through listener callbacks {@link ActionListener#onSuccess} or
|
||||
* {@link ActionListener#onFailure}.
|
||||
*
|
||||
* <p>The persistent p2p group list stored in the system can be obtained by
|
||||
* {@link #requestPersistentGroupInfo(Channel, PersistentGroupInfoListener)} and
|
||||
* a network id can be obtained by {@link WifiP2pGroup#getNetworkId()}.
|
||||
*
|
||||
* @param c is the channel created at {@link #initialize}
|
||||
* @param netId he network id of the p2p group.
|
||||
* @param listener for callbacks on success or failure. Can be null.
|
||||
* @hide
|
||||
*/
|
||||
public void deletePersistentGroup(Channel c, int netId, ActionListener listener) {
|
||||
checkChannel(c);
|
||||
c.mAsyncChannel.sendMessage(DELETE_PERSISTENT_GROUP, netId, c.putListener(listener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a list of all the persistent p2p groups stored in system.
|
||||
*
|
||||
* @param c is the channel created at {@link #initialize}
|
||||
* @param listener for callback when persistent group info list is available. Can be null.
|
||||
* @hide
|
||||
*/
|
||||
public void requestPersistentGroupInfo(Channel c, PersistentGroupInfoListener listener) {
|
||||
checkChannel(c);
|
||||
c.mAsyncChannel.sendMessage(REQUEST_PERSISTENT_GROUP_INFO, 0, c.putListener(listener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to WifiP2pService handler. This is used to establish
|
||||
* an AsyncChannel communication with WifiService
|
||||
|
@ -45,6 +45,7 @@ import android.net.wifi.WifiMonitor;
|
||||
import android.net.wifi.WifiNative;
|
||||
import android.net.wifi.WifiStateMachine;
|
||||
import android.net.wifi.WpsInfo;
|
||||
import android.net.wifi.p2p.WifiP2pGroupList.GroupDeleteListener;
|
||||
import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
|
||||
import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
|
||||
import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
|
||||
@ -118,6 +119,13 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
private static final Boolean JOIN_GROUP = true;
|
||||
private static final Boolean FORM_GROUP = false;
|
||||
|
||||
private static final Boolean TRY_REINVOCATION = true;;
|
||||
private static final Boolean NO_REINVOCATION = false;
|
||||
|
||||
private static final int CONNECT_FAILURE = -1;
|
||||
private static final int CONNECT_SUCCESS = 0;
|
||||
private static final int NEEDS_PROVISION_REQ = 1;
|
||||
|
||||
/* Two minutes comes from the wpa_supplicant setting */
|
||||
private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000;
|
||||
private static int mGroupCreatingTimeoutIndex = 0;
|
||||
@ -191,6 +199,84 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
private static final String[] DHCP_RANGE = {"192.168.49.2", "192.168.49.254"};
|
||||
private static final String SERVER_ADDRESS = "192.168.49.1";
|
||||
|
||||
/**
|
||||
* Error code definition.
|
||||
* see the Table.8 in the WiFi Direct specification for the detail.
|
||||
*/
|
||||
public static enum P2pStatus {
|
||||
/* Success. */
|
||||
SUCCESS,
|
||||
|
||||
/* The target device is currently unavailable. */
|
||||
INFORMATION_IS_CURRENTLY_UNAVAILABLE,
|
||||
|
||||
/* Protocol error. */
|
||||
INCOMPATIBLE_PARAMETERS,
|
||||
|
||||
/* The target device reached the limit of the number of the connectable device.
|
||||
* For example, device limit or group limit is set. */
|
||||
LIMIT_REACHED,
|
||||
|
||||
/* Protocol error. */
|
||||
INVALID_PARAMETER,
|
||||
|
||||
/* Unable to accommodate request. */
|
||||
UNABLE_TO_ACCOMMODATE_REQUEST,
|
||||
|
||||
/* Previous protocol error, or disruptive behavior. */
|
||||
PREVIOUS_PROTOCOL_ERROR,
|
||||
|
||||
/* There is no common channels the both devices can use. */
|
||||
NO_COMMON_CHANNE,
|
||||
|
||||
/* Unknown p2p group. For example, Device A tries to invoke the previous persistent group,
|
||||
* but device B has removed the specified credential already. */
|
||||
UNKNOWN_P2P_GROUP,
|
||||
|
||||
/* Both p2p devices indicated an intent of 15 in group owner negotiation. */
|
||||
BOTH_GO_INTENT_15,
|
||||
|
||||
/* Incompatible provisioning method. */
|
||||
INCOMPATIBLE_PROVISIONING_METHOD,
|
||||
|
||||
/* Rejected by user */
|
||||
REJECTED_BY_USER,
|
||||
|
||||
/* Unknown error */
|
||||
UNKNOWN;
|
||||
|
||||
public static P2pStatus valueOf(int error) {
|
||||
switch(error) {
|
||||
case 0 :
|
||||
return SUCCESS;
|
||||
case 1:
|
||||
return INFORMATION_IS_CURRENTLY_UNAVAILABLE;
|
||||
case 2:
|
||||
return INCOMPATIBLE_PARAMETERS;
|
||||
case 3:
|
||||
return LIMIT_REACHED;
|
||||
case 4:
|
||||
return INVALID_PARAMETER;
|
||||
case 5:
|
||||
return UNABLE_TO_ACCOMMODATE_REQUEST;
|
||||
case 6:
|
||||
return PREVIOUS_PROTOCOL_ERROR;
|
||||
case 7:
|
||||
return NO_COMMON_CHANNE;
|
||||
case 8:
|
||||
return UNKNOWN_P2P_GROUP;
|
||||
case 9:
|
||||
return BOTH_GO_INTENT_15;
|
||||
case 10:
|
||||
return INCOMPATIBLE_PROVISIONING_METHOD;
|
||||
case 11:
|
||||
return REJECTED_BY_USER;
|
||||
default:
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public WifiP2pService(Context context) {
|
||||
mContext = context;
|
||||
|
||||
@ -273,6 +359,16 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
private WifiMonitor mWifiMonitor = new WifiMonitor(this, mWifiNative);
|
||||
|
||||
private WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
|
||||
private WifiP2pGroupList mGroups = new WifiP2pGroupList(
|
||||
new GroupDeleteListener() {
|
||||
@Override
|
||||
public void onDeleteGroup(int netId) {
|
||||
if (DBG) logd("called onDeleteGroup() netId=" + netId);
|
||||
mWifiNative.removeNetwork(netId);
|
||||
mWifiNative.saveConfig();
|
||||
sendP2pPersistentGroupsChangedBroadcast();
|
||||
}
|
||||
});
|
||||
private WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
|
||||
private WifiP2pGroup mGroup;
|
||||
|
||||
@ -395,6 +491,10 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
|
||||
WifiP2pManager.BUSY);
|
||||
break;
|
||||
case WifiP2pManager.DELETE_PERSISTENT_GROUP:
|
||||
replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
|
||||
WifiP2pManager.BUSY);
|
||||
break;
|
||||
case WifiP2pManager.REQUEST_PEERS:
|
||||
replyToMessage(message, WifiP2pManager.RESPONSE_PEERS, mPeers);
|
||||
break;
|
||||
@ -404,6 +504,10 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
case WifiP2pManager.REQUEST_GROUP_INFO:
|
||||
replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, mGroup);
|
||||
break;
|
||||
case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
|
||||
replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO,
|
||||
mGroups);
|
||||
break;
|
||||
case WifiP2pManager.SET_DIALOG_LISTENER:
|
||||
String appPkgName = (String)message.getData().getString(
|
||||
WifiP2pManager.APP_PKG_BUNDLE_KEY);
|
||||
@ -520,6 +624,10 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
|
||||
WifiP2pManager.P2P_UNSUPPORTED);
|
||||
break;
|
||||
case WifiP2pManager.DELETE_PERSISTENT_GROUP:
|
||||
replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
|
||||
WifiP2pManager.P2P_UNSUPPORTED);
|
||||
break;
|
||||
default:
|
||||
return NOT_HANDLED;
|
||||
}
|
||||
@ -626,6 +734,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
break;
|
||||
case WifiStateMachine.CMD_DISABLE_P2P:
|
||||
if (mPeers.clear()) sendP2pPeersChangedBroadcast();
|
||||
if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
|
||||
|
||||
mWifiNative.closeSupplicantConnection();
|
||||
transitionTo(mP2pDisablingState);
|
||||
break;
|
||||
@ -734,6 +844,11 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
sendServiceResponse(resp);
|
||||
}
|
||||
break;
|
||||
case WifiP2pManager.DELETE_PERSISTENT_GROUP:
|
||||
if (DBG) logd(getName() + " delete persistent group");
|
||||
mGroups.remove(message.arg1);
|
||||
replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED);
|
||||
break;
|
||||
default:
|
||||
return NOT_HANDLED;
|
||||
}
|
||||
@ -768,47 +883,35 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
/* Update group capability before connect */
|
||||
int gc = mWifiNative.getGroupCapability(config.deviceAddress);
|
||||
mPeers.updateGroupCapability(config.deviceAddress, gc);
|
||||
|
||||
if (mSavedPeerConfig != null && config.deviceAddress.equals(
|
||||
mSavedPeerConfig.deviceAddress)) {
|
||||
mSavedPeerConfig = config;
|
||||
|
||||
//Stop discovery before issuing connect
|
||||
mWifiNative.p2pStopFind();
|
||||
if (mPeers.isGroupOwner(mSavedPeerConfig.deviceAddress)) {
|
||||
p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP);
|
||||
} else {
|
||||
p2pConnectWithPinDisplay(mSavedPeerConfig, FORM_GROUP);
|
||||
}
|
||||
transitionTo(mGroupNegotiationState);
|
||||
} else {
|
||||
mSavedPeerConfig = config;
|
||||
int netId = configuredNetworkId(mSavedPeerConfig.deviceAddress);
|
||||
if (netId >= 0) {
|
||||
//TODO: if failure, remove config and do a regular p2pConnect()
|
||||
mWifiNative.p2pReinvoke(netId, mSavedPeerConfig.deviceAddress);
|
||||
} else {
|
||||
//Stop discovery before issuing connect
|
||||
mWifiNative.p2pStopFind();
|
||||
//If peer is a GO, we do not need to send provisional discovery,
|
||||
//the supplicant takes care of it.
|
||||
if (mPeers.isGroupOwner(mSavedPeerConfig.deviceAddress)) {
|
||||
if (DBG) logd("Sending join to GO");
|
||||
p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP);
|
||||
transitionTo(mGroupNegotiationState);
|
||||
} else {
|
||||
if (DBG) logd("Sending prov disc");
|
||||
transitionTo(mProvisionDiscoveryState);
|
||||
}
|
||||
}
|
||||
int connectRet = connect(config, TRY_REINVOCATION);
|
||||
if (connectRet == CONNECT_FAILURE) {
|
||||
replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
|
||||
break;
|
||||
}
|
||||
mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
|
||||
sendP2pPeersChangedBroadcast();
|
||||
replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
|
||||
if (connectRet == NEEDS_PROVISION_REQ) {
|
||||
if (DBG) logd("Sending prov disc");
|
||||
transitionTo(mProvisionDiscoveryState);
|
||||
break;
|
||||
}
|
||||
transitionTo(mGroupNegotiationState);
|
||||
break;
|
||||
case WifiP2pManager.STOP_DISCOVERY:
|
||||
if (mWifiNative.p2pStopFind()) {
|
||||
// When discovery stops in inactive state, flush to clear
|
||||
// state peer data
|
||||
mWifiNative.p2pFlush();
|
||||
mServiceDiscReqId = null;
|
||||
replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
|
||||
} else {
|
||||
replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
|
||||
WifiP2pManager.ERROR);
|
||||
}
|
||||
break;
|
||||
case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT:
|
||||
mSavedPeerConfig = (WifiP2pConfig) message.obj;
|
||||
|
||||
mAutonomousGroup = false;
|
||||
mJoinExistingGroup = false;
|
||||
if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
|
||||
@ -848,13 +951,6 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
transitionTo(mUserAuthorizingInvitationState);
|
||||
}
|
||||
break;
|
||||
case WifiMonitor.P2P_FIND_STOPPED_EVENT:
|
||||
// When discovery stops in inactive state, flush to clear
|
||||
// state peer data
|
||||
mWifiNative.p2pFlush();
|
||||
mServiceDiscReqId = null;
|
||||
sendP2pDiscoveryChangedBroadcast(false);
|
||||
break;
|
||||
case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
|
||||
case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
|
||||
case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
|
||||
@ -865,13 +961,41 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
break;
|
||||
case WifiP2pManager.CREATE_GROUP:
|
||||
mAutonomousGroup = true;
|
||||
if (mWifiNative.p2pGroupAdd()) {
|
||||
int netId = message.arg1;
|
||||
boolean ret = false;
|
||||
if (netId == WifiP2pGroup.PERSISTENT_NET_ID) {
|
||||
// check if the go persistent group is present.
|
||||
netId = mGroups.getNetworkId(mThisDevice.deviceAddress);
|
||||
if (netId != -1) {
|
||||
ret = mWifiNative.p2pGroupAdd(netId);
|
||||
} else {
|
||||
ret = mWifiNative.p2pGroupAdd(true);
|
||||
}
|
||||
} else {
|
||||
ret = mWifiNative.p2pGroupAdd(false);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED);
|
||||
transitionTo(mGroupNegotiationState);
|
||||
} else {
|
||||
replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
|
||||
WifiP2pManager.ERROR);
|
||||
// remain at this state.
|
||||
}
|
||||
break;
|
||||
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
|
||||
mGroup = (WifiP2pGroup) message.obj;
|
||||
if (DBG) logd(getName() + " group started");
|
||||
|
||||
if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
|
||||
// This is an invocation case.
|
||||
mAutonomousGroup = false;
|
||||
deferMessage(message);
|
||||
transitionTo(mGroupNegotiationState);
|
||||
} else {
|
||||
return NOT_HANDLED;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return NOT_HANDLED;
|
||||
@ -941,11 +1065,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
@Override
|
||||
public void enter() {
|
||||
if (DBG) logd(getName());
|
||||
if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
|
||||
mSavedPeerConfig)) {
|
||||
notifyInvitationReceived();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processMessage(Message message) {
|
||||
@ -953,11 +1074,10 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
boolean ret = HANDLED;
|
||||
switch (message.what) {
|
||||
case PEER_CONNECTION_USER_ACCEPT:
|
||||
//TODO: handle persistence
|
||||
if (mJoinExistingGroup) {
|
||||
p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP);
|
||||
} else {
|
||||
p2pConnectWithPinDisplay(mSavedPeerConfig, FORM_GROUP);
|
||||
if (connect(mSavedPeerConfig, TRY_REINVOCATION) == CONNECT_FAILURE) {
|
||||
handleGroupCreationFailure();
|
||||
transitionTo(mInactiveState);
|
||||
break;
|
||||
}
|
||||
mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
|
||||
sendP2pPeersChangedBroadcast();
|
||||
@ -1017,9 +1137,12 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
transitionTo(mGroupNegotiationState);
|
||||
} else {
|
||||
mJoinExistingGroup = false;
|
||||
if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress),
|
||||
mSavedPeerConfig)) {
|
||||
transitionTo(mUserAuthorizingInvitationState);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
|
||||
provDisc = (WifiP2pProvDiscEvent) message.obj;
|
||||
@ -1062,6 +1185,17 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
|
||||
mGroup = (WifiP2pGroup) message.obj;
|
||||
if (DBG) logd(getName() + " group started");
|
||||
|
||||
if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
|
||||
/*
|
||||
* update cache information and set network id to mGroup.
|
||||
*/
|
||||
updatePersistentNetworks();
|
||||
String devAddr = mGroup.getOwner().deviceAddress;
|
||||
mGroup.setNetworkId(mGroups.getNetworkId(devAddr,
|
||||
mGroup.getNetworkName()));
|
||||
}
|
||||
|
||||
if (mGroup.isGroupOwner()) {
|
||||
startDhcpServer(mGroup.getInterface());
|
||||
} else {
|
||||
@ -1090,6 +1224,29 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
// failure causes supplicant issues. Ignore right now.
|
||||
case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
|
||||
break;
|
||||
case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
|
||||
P2pStatus status = (P2pStatus)message.obj;
|
||||
if (status == P2pStatus.SUCCESS) {
|
||||
// invocation was succeeded.
|
||||
// wait P2P_GROUP_STARTED_EVENT.
|
||||
break;
|
||||
} else if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
|
||||
// target device has already removed the credential.
|
||||
// So, remove this credential accordingly.
|
||||
int netId = mSavedPeerConfig.netId;
|
||||
if (netId >= 0) {
|
||||
if (DBG) logd("Remove unknown client from the list");
|
||||
removeClientFromList(netId, mSavedPeerConfig.deviceAddress, true);
|
||||
}
|
||||
}
|
||||
|
||||
// invocation is failed or deferred. Try another way to connect.
|
||||
mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID;
|
||||
if (connect(mSavedPeerConfig, NO_REINVOCATION) == CONNECT_FAILURE) {
|
||||
handleGroupCreationFailure();
|
||||
transitionTo(mInactiveState);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return NOT_HANDLED;
|
||||
}
|
||||
@ -1152,7 +1309,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
}
|
||||
}
|
||||
sendP2pPeersChangedBroadcast();
|
||||
if (DBG) loge(getName() + " ap sta disconnected");
|
||||
if (DBG) logd(getName() + " ap sta disconnected");
|
||||
} else {
|
||||
loge("Disconnect on unknown device: " + device);
|
||||
}
|
||||
@ -1172,7 +1329,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
}
|
||||
break;
|
||||
case WifiP2pManager.REMOVE_GROUP:
|
||||
if (DBG) loge(getName() + " remove group");
|
||||
if (DBG) logd(getName() + " remove group");
|
||||
if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) {
|
||||
replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
|
||||
} else {
|
||||
@ -1181,7 +1338,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
}
|
||||
break;
|
||||
case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
|
||||
if (DBG) loge(getName() + " group removed");
|
||||
if (DBG) logd(getName() + " group removed");
|
||||
Collection <WifiP2pDevice> devices = mGroup.getClientList();
|
||||
boolean changed = false;
|
||||
for (WifiP2pDevice d : mPeers.getDeviceList()) {
|
||||
@ -1252,6 +1409,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
|
||||
} else {
|
||||
logd("Inviting device : " + config.deviceAddress);
|
||||
mSavedPeerConfig = config;
|
||||
if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
|
||||
mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
|
||||
sendP2pPeersChangedBroadcast();
|
||||
@ -1263,6 +1421,29 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
}
|
||||
// TODO: figure out updating the status to declined when invitation is rejected
|
||||
break;
|
||||
case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
|
||||
P2pStatus status = (P2pStatus)message.obj;
|
||||
logd("===> INVITATION RESULT EVENT : " + status);
|
||||
if (status == P2pStatus.SUCCESS) {
|
||||
// invocation was succeeded.
|
||||
break;
|
||||
} else if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
|
||||
// target device has already removed the credential.
|
||||
// So, remove this credential accordingly.
|
||||
int netId = mGroup.getNetworkId();
|
||||
if (netId >= 0) {
|
||||
if (DBG) logd("Remove unknown client from the list");
|
||||
if (!removeClientFromList(netId,
|
||||
mSavedPeerConfig.deviceAddress, false)) {
|
||||
// not found the client on the list
|
||||
Slog.e(TAG, "Already removed the client, ignore");
|
||||
break;
|
||||
}
|
||||
// try invitation.
|
||||
sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
|
||||
case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
|
||||
case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
|
||||
@ -1304,7 +1485,6 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
@Override
|
||||
public void enter() {
|
||||
if (DBG) logd(getName());
|
||||
|
||||
notifyInvitationReceived();
|
||||
}
|
||||
|
||||
@ -1394,6 +1574,13 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
mContext.sendStickyBroadcast(intent);
|
||||
}
|
||||
|
||||
private void sendP2pPersistentGroupsChangedBroadcast() {
|
||||
if (DBG) logd("sending p2p persistent groups changed broadcast");
|
||||
Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
mContext.sendStickyBroadcast(intent);
|
||||
}
|
||||
|
||||
private void startDhcpServer(String intf) {
|
||||
InterfaceConfiguration ifcg = null;
|
||||
try {
|
||||
@ -1520,11 +1707,246 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
//TODO: implement when wpa_supplicant is fixed
|
||||
private int configuredNetworkId(String deviceAddress) {
|
||||
/**
|
||||
* Synchronize the persistent group list between
|
||||
* wpa_supplicant and mGroups.
|
||||
*/
|
||||
private void updatePersistentNetworks() {
|
||||
String listStr = mWifiNative.listNetworks();
|
||||
|
||||
boolean isSaveRequired = false;
|
||||
String[] lines = listStr.split("\n");
|
||||
// Skip the first line, which is a header
|
||||
for (int i = 1; i < lines.length; i++) {
|
||||
String[] result = lines[i].split("\t");
|
||||
if (result == null || result.length < 4) {
|
||||
continue;
|
||||
}
|
||||
// network-id | ssid | bssid | flags
|
||||
int netId = -1;
|
||||
String ssid = result[1];
|
||||
String bssid = result[2];
|
||||
String flags = result[3];
|
||||
try {
|
||||
netId = Integer.parseInt(result[0]);
|
||||
} catch(NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flags.indexOf("[CURRENT]") != -1) {
|
||||
continue;
|
||||
}
|
||||
if (flags.indexOf("[P2P-PERSISTENT]") == -1) {
|
||||
/*
|
||||
* The unused profile is sometimes remained when the p2p group formation is failed.
|
||||
* So, we clean up the p2p group here.
|
||||
*/
|
||||
if (DBG) logd("clean up the unused persistent group. netId=" + netId);
|
||||
mWifiNative.removeNetwork(netId);
|
||||
isSaveRequired = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mGroups.contains(netId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WifiP2pGroup group = new WifiP2pGroup();
|
||||
group.setNetworkId(netId);
|
||||
group.setNetworkName(ssid);
|
||||
String mode = mWifiNative.getNetworkVariable(netId, "mode");
|
||||
if (mode != null && mode.equals("3")) {
|
||||
group.setIsGroupOwner(true);
|
||||
}
|
||||
if (bssid.equalsIgnoreCase(mThisDevice.deviceAddress)) {
|
||||
group.setOwner(mThisDevice);
|
||||
} else {
|
||||
WifiP2pDevice device = new WifiP2pDevice();
|
||||
device.deviceAddress = bssid;
|
||||
group.setOwner(device);
|
||||
}
|
||||
mGroups.add(group);
|
||||
isSaveRequired = true;
|
||||
}
|
||||
|
||||
if (isSaveRequired) {
|
||||
sendP2pPersistentGroupsChangedBroadcast();
|
||||
mWifiNative.saveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to connect to the target device.
|
||||
*
|
||||
* Use the persistent credential if it has been stored.
|
||||
*
|
||||
* @param config
|
||||
* @param tryInvocation if true, try to invoke. Otherwise, never try to invoke.
|
||||
* @return
|
||||
*/
|
||||
private int connect(WifiP2pConfig config, boolean tryInvocation) {
|
||||
|
||||
if (config == null) {
|
||||
loge("invalid argument.");
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
|
||||
boolean isResp = (mSavedPeerConfig != null &&
|
||||
config.deviceAddress.equals(mSavedPeerConfig.deviceAddress));
|
||||
mSavedPeerConfig = config;
|
||||
|
||||
WifiP2pDevice dev = mPeers.get(config.deviceAddress);
|
||||
if (dev == null) {
|
||||
loge("target device is not found.");
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
|
||||
boolean join = dev.isGroupOwner();
|
||||
String ssid = mWifiNative.p2pGetSsid(dev.deviceAddress);
|
||||
if (DBG) logd("target ssid is " + ssid + " join:" + join);
|
||||
|
||||
if (join && dev.isGroupLimit()) {
|
||||
if (DBG) logd("target device reaches group limit.");
|
||||
|
||||
// if the target group has reached the limit,
|
||||
// try group formation.
|
||||
join = false;
|
||||
} else if (join) {
|
||||
int netId = mGroups.getNetworkId(dev.deviceAddress, ssid);
|
||||
if (netId >= 0) {
|
||||
// Skip WPS and start 4way handshake immediately.
|
||||
if (!mWifiNative.p2pGroupAdd(netId)) {
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
return CONNECT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (!join && dev.isDeviceLimit()) {
|
||||
loge("target device reaches the device limit.");
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
|
||||
if (!join && tryInvocation && dev.isInvitationCapable()) {
|
||||
int netId = WifiP2pGroup.PERSISTENT_NET_ID;
|
||||
if (config.netId >= 0) {
|
||||
if (config.deviceAddress.equals(mGroups.getOwnerAddr(config.netId))) {
|
||||
netId = config.netId;
|
||||
}
|
||||
} else {
|
||||
netId = mGroups.getNetworkId(dev.deviceAddress);
|
||||
}
|
||||
if (netId < 0) {
|
||||
netId = getNetworkIdFromClientList(dev.deviceAddress);
|
||||
}
|
||||
if (DBG) logd("netId related with " + dev.deviceAddress + " = " + netId);
|
||||
if (netId >= 0) {
|
||||
|
||||
// Invoke the persistent group.
|
||||
if (!mWifiNative.p2pReinvoke(netId, dev.deviceAddress)) {
|
||||
loge("p2pReinvoke() failed");
|
||||
return CONNECT_FAILURE;
|
||||
}
|
||||
// Save network id. It'll be used when an invitation result event is received.
|
||||
mSavedPeerConfig.netId = netId;
|
||||
return CONNECT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
//Stop discovery before issuing connect
|
||||
mWifiNative.p2pStopFind();
|
||||
|
||||
if (!isResp) {
|
||||
return NEEDS_PROVISION_REQ;
|
||||
}
|
||||
|
||||
p2pConnectWithPinDisplay(config, join);
|
||||
return CONNECT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the network id of the group owner profile which has the p2p client with
|
||||
* the specified device address in it's client list.
|
||||
* If more than one persistent group of the same address is present in its client
|
||||
* lists, return the first one.
|
||||
*
|
||||
* @param deviceAddress p2p device address.
|
||||
* @return the network id. if not found, return -1.
|
||||
*/
|
||||
private int getNetworkIdFromClientList(String deviceAddress) {
|
||||
if (deviceAddress == null) return -1;
|
||||
|
||||
Collection<WifiP2pGroup> groups = mGroups.getGroupList();
|
||||
for (WifiP2pGroup group : groups) {
|
||||
int netId = group.getNetworkId();
|
||||
String[] p2pClientList = getClientList(netId);
|
||||
if (p2pClientList == null) continue;
|
||||
for (String client : p2pClientList) {
|
||||
if (deviceAddress.equalsIgnoreCase(client)) {
|
||||
return netId;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return p2p client list associated with the specified network id.
|
||||
* @param netId network id.
|
||||
* @return p2p client list. if not found, return null.
|
||||
*/
|
||||
private String[] getClientList(int netId) {
|
||||
String p2pClients = mWifiNative.getNetworkVariable(netId, "p2p_client_list");
|
||||
if (p2pClients == null) {
|
||||
return null;
|
||||
}
|
||||
return p2pClients.split(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified p2p client from the specified profile.
|
||||
* @param netId network id of the profile.
|
||||
* @param addr p2p client address to be removed.
|
||||
* @param isRemovable if true, remove the specified profile if its client list becomes empty.
|
||||
* @return whether removing the specified p2p client is successful or not.
|
||||
*/
|
||||
private boolean removeClientFromList(int netId, String addr, boolean isRemovable) {
|
||||
StringBuilder modifiedClientList = new StringBuilder();
|
||||
String[] currentClientList = getClientList(netId);
|
||||
boolean isClientRemoved = false;
|
||||
if (currentClientList != null) {
|
||||
for (String client : currentClientList) {
|
||||
if (!client.equalsIgnoreCase(addr)) {
|
||||
modifiedClientList.append(" ");
|
||||
modifiedClientList.append(client);
|
||||
} else {
|
||||
isClientRemoved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modifiedClientList.length() == 0 && isRemovable) {
|
||||
// the client list is empty. so remove it.
|
||||
if (DBG) logd("Remove unknown network");
|
||||
mGroups.remove(netId);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isClientRemoved) {
|
||||
// specified p2p client is not found. already removed.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DBG) logd("Modified client list: " + modifiedClientList);
|
||||
if (modifiedClientList.length() == 0) {
|
||||
modifiedClientList.append("\"\"");
|
||||
}
|
||||
mWifiNative.setNetworkVariable(netId,
|
||||
"p2p_client_list", modifiedClientList.toString());
|
||||
mWifiNative.saveConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setWifiP2pInfoOnGroupFormation(String serverAddress) {
|
||||
mWifiP2pInfo.groupFormed = true;
|
||||
mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner();
|
||||
@ -1610,6 +2032,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
mWifiNative.p2pServiceFlush();
|
||||
mServiceTransactionId = 0;
|
||||
mServiceDiscReqId = null;
|
||||
|
||||
updatePersistentNetworks();
|
||||
}
|
||||
|
||||
private void updateThisDevice(int status) {
|
||||
@ -1738,7 +2162,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
//Application does not have transaction id information
|
||||
//go through stored requests to remove
|
||||
boolean removed = false;
|
||||
for (int i=0; i < clientInfo.mReqList.size(); i++) {
|
||||
for (int i=0; i<clientInfo.mReqList.size(); i++) {
|
||||
if (req.equals(clientInfo.mReqList.valueAt(i))) {
|
||||
removed = true;
|
||||
clientInfo.mReqList.removeAt(i);
|
||||
@ -2077,5 +2501,4 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
mServList = new ArrayList<WifiP2pServiceInfo>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user