diff options
author | Irfan Sheriff <isheriff@android.com> | 2012-08-27 17:54:07 -0700 |
---|---|---|
committer | android code review <noreply-gerritcodereview@google.com> | 2012-08-27 17:54:07 -0700 |
commit | 67ea8c86419ffbf603052e816d6b1e9e7e20fbb9 (patch) | |
tree | 0449b8cb11ad2c5cbc1200d95088d55cf2ab1cac /wifi | |
parent | 32d1fec50baaecdea34ae2a47ca808e8e4181ed2 (diff) | |
parent | 0879d03f0a5caa108a0a7320442d57629f9ced81 (diff) | |
download | frameworks_base-67ea8c86419ffbf603052e816d6b1e9e7e20fbb9.zip frameworks_base-67ea8c86419ffbf603052e816d6b1e9e7e20fbb9.tar.gz frameworks_base-67ea8c86419ffbf603052e816d6b1e9e7e20fbb9.tar.bz2 |
Merge "Added a persistent feature in WiFi Direct."
Diffstat (limited to 'wifi')
-rw-r--r-- | wifi/java/android/net/wifi/WifiMonitor.java | 12 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiNative.java | 37 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pConfig.java | 20 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pDevice.java | 15 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pGroup.java | 58 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl | 19 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java | 229 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pManager.java | 76 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pService.java | 553 |
9 files changed, 927 insertions, 92 deletions
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java index a447c86..17c930b 100644 --- a/wifi/java/android/net/wifi/WifiMonitor.java +++ b/wifi/java/android/net/wifi/WifiMonitor.java @@ -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)); diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index 4bf1ca3..e520185 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -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> diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java index 6aea090..100e062 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java @@ -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; } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java index afdc9be..c86ec8b 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java @@ -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; diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java index c30cc73..bc492b3 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java @@ -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; } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl new file mode 100644 index 0000000..3d8a476 --- /dev/null +++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl @@ -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;
\ No newline at end of file diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java new file mode 100644 index 0000000..3459a5a --- /dev/null +++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java @@ -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]; + } + }; +} diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index 2c25e9d..96d3a7f 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -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; @@ -267,6 +267,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)}. * @hide @@ -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)); } /** @@ -1297,6 +1335,40 @@ public class WifiP2pManager { } /** + * 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 * diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java index 5759074..0212552 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java @@ -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,16 +961,44 @@ public class WifiP2pService extends IWifiP2pManager.Stub { break; case WifiP2pManager.CREATE_GROUP: mAutonomousGroup = true; - if (mWifiNative.p2pGroupAdd()) { - replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED); + 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 { - replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, - WifiP2pManager.ERROR); + return NOT_HANDLED; } - transitionTo(mGroupNegotiationState); break; default: - return NOT_HANDLED; + return NOT_HANDLED; } return HANDLED; } @@ -941,10 +1065,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { @Override public void enter() { if (DBG) logd(getName()); - if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress), - mSavedPeerConfig)) { - notifyInvitationReceived(); - } + notifyInvitationReceived(); } @Override @@ -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,7 +1137,10 @@ public class WifiP2pService extends IWifiP2pManager.Stub { transitionTo(mGroupNegotiationState); } else { mJoinExistingGroup = false; - transitionTo(mUserAuthorizingInvitationState); + if (!sendConnectNoticeToApp(mPeers.get(mSavedPeerConfig.deviceAddress), + mSavedPeerConfig)) { + transitionTo(mUserAuthorizingInvitationState); + } } } break; @@ -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>(); } } - } |