Home | History | Annotate | Download | only in p2p
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net.wifi.p2p;
     18 
     19 import android.os.Parcelable;
     20 import android.os.Parcel;
     21 
     22 import java.util.ArrayList;
     23 import java.util.List;
     24 import java.util.Collection;
     25 import java.util.Collections;
     26 import java.util.regex.Pattern;
     27 import java.util.regex.Matcher;
     28 
     29 /**
     30  * A class representing a Wi-Fi P2p group. A p2p group consists of a single group
     31  * owner and one or more clients. In the case of a group with only two devices, one
     32  * will be the group owner and the other will be a group client.
     33  *
     34  * {@see WifiP2pManager}
     35  */
     36 public class WifiP2pGroup implements Parcelable {
     37 
     38     /** The temporary network id.
     39      * {@hide} */
     40     public static final int TEMPORARY_NET_ID = -1;
     41 
     42     /** The persistent network id.
     43      * If a matching persistent profile is found, use it.
     44      * Otherwise, create a new persistent profile.
     45      * {@hide} */
     46     public static final int PERSISTENT_NET_ID = -2;
     47 
     48     /** The network name */
     49     private String mNetworkName;
     50 
     51     /** Group owner */
     52     private WifiP2pDevice mOwner;
     53 
     54     /** Device is group owner */
     55     private boolean mIsGroupOwner;
     56 
     57     /** Group clients */
     58     private List<WifiP2pDevice> mClients = new ArrayList<WifiP2pDevice>();
     59 
     60     /** The passphrase used for WPA2-PSK */
     61     private String mPassphrase;
     62 
     63     private String mInterface;
     64 
     65     /** The network id in the wpa_supplicant */
     66     private int mNetId;
     67 
     68     /** P2P group started string pattern */
     69     private static final Pattern groupStartedPattern = Pattern.compile(
     70         "ssid=\"(.+)\" " +
     71         "freq=(\\d+) " +
     72         "(?:psk=)?([0-9a-fA-F]{64})?" +
     73         "(?:passphrase=)?(?:\"(.{0,63})\")? " +
     74         "go_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2})" +
     75         " ?(\\[PERSISTENT\\])?"
     76     );
     77 
     78     public WifiP2pGroup() {
     79     }
     80 
     81     /**
     82      * @param supplicantEvent formats supported include
     83      *
     84      *  P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437
     85      *  [psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|
     86      *  passphrase="fKG4jMe3"] go_dev_addr=fa:7b:7a:42:02:13 [PERSISTENT]
     87      *
     88      *  P2P-GROUP-REMOVED p2p-wlan0-0 [client|GO] reason=REQUESTED
     89      *
     90      *  P2P-INVITATION-RECEIVED sa=fa:7b:7a:42:02:13 go_dev_addr=f8:7b:7a:42:02:13
     91      *  bssid=fa:7b:7a:42:82:13 unknown-network
     92      *
     93      *  P2P-INVITATION-RECEIVED sa=b8:f9:34:2a:c7:9d persistent=0
     94      *
     95      *  Note: The events formats can be looked up in the wpa_supplicant code
     96      *  @hide
     97      */
     98     public WifiP2pGroup(String supplicantEvent) throws IllegalArgumentException {
     99 
    100         String[] tokens = supplicantEvent.split(" ");
    101 
    102         if (tokens.length < 3) {
    103             throw new IllegalArgumentException("Malformed supplicant event");
    104         }
    105 
    106         if (tokens[0].startsWith("P2P-GROUP")) {
    107             mInterface = tokens[1];
    108             mIsGroupOwner = tokens[2].equals("GO");
    109 
    110             Matcher match = groupStartedPattern.matcher(supplicantEvent);
    111             if (!match.find()) {
    112                 return;
    113             }
    114 
    115             mNetworkName = match.group(1);
    116             //freq and psk are unused right now
    117             //int freq = Integer.parseInt(match.group(2));
    118             //String psk = match.group(3);
    119             mPassphrase = match.group(4);
    120             mOwner = new WifiP2pDevice(match.group(5));
    121             if (match.group(6) != null) {
    122                 mNetId = PERSISTENT_NET_ID;
    123             } else {
    124                 mNetId = TEMPORARY_NET_ID;
    125             }
    126         } else if (tokens[0].equals("P2P-INVITATION-RECEIVED")) {
    127             String sa = null;
    128             mNetId = PERSISTENT_NET_ID;
    129             for (String token : tokens) {
    130                 String[] nameValue = token.split("=");
    131                 if (nameValue.length != 2) continue;
    132 
    133                 if (nameValue[0].equals("sa")) {
    134                     sa = nameValue[1];
    135 
    136                     // set source address into the client list.
    137                     WifiP2pDevice dev = new WifiP2pDevice();
    138                     dev.deviceAddress = nameValue[1];
    139                     mClients.add(dev);
    140                     continue;
    141                 }
    142 
    143                 if (nameValue[0].equals("go_dev_addr")) {
    144                     mOwner = new WifiP2pDevice(nameValue[1]);
    145                     continue;
    146                 }
    147 
    148                 if (nameValue[0].equals("persistent")) {
    149                     mNetId = Integer.parseInt(nameValue[1]);
    150                     continue;
    151                 }
    152             }
    153         } else {
    154             throw new IllegalArgumentException("Malformed supplicant event");
    155         }
    156     }
    157 
    158     /** @hide */
    159     public void setNetworkName(String networkName) {
    160         mNetworkName = networkName;
    161     }
    162 
    163     /**
    164      * Get the network name (SSID) of the group. Legacy Wi-Fi clients will discover
    165      * the p2p group using the network name.
    166      */
    167     public String getNetworkName() {
    168         return mNetworkName;
    169     }
    170 
    171     /** @hide */
    172     public void setIsGroupOwner(boolean isGo) {
    173         mIsGroupOwner = isGo;
    174     }
    175 
    176     /** Check whether this device is the group owner of the created p2p group */
    177     public boolean isGroupOwner() {
    178         return mIsGroupOwner;
    179     }
    180 
    181     /** @hide */
    182     public void setOwner(WifiP2pDevice device) {
    183         mOwner = device;
    184     }
    185 
    186     /** Get the details of the group owner as a {@link WifiP2pDevice} object */
    187     public WifiP2pDevice getOwner() {
    188         return mOwner;
    189     }
    190 
    191     /** @hide */
    192     public void addClient(String address) {
    193         addClient(new WifiP2pDevice(address));
    194     }
    195 
    196     /** @hide */
    197     public void addClient(WifiP2pDevice device) {
    198         for (WifiP2pDevice client : mClients) {
    199             if (client.equals(device)) return;
    200         }
    201         mClients.add(device);
    202     }
    203 
    204     /** @hide */
    205     public boolean removeClient(String address) {
    206         return mClients.remove(new WifiP2pDevice(address));
    207     }
    208 
    209     /** @hide */
    210     public boolean removeClient(WifiP2pDevice device) {
    211         return mClients.remove(device);
    212     }
    213 
    214     /** @hide */
    215     public boolean isClientListEmpty() {
    216         return mClients.size() == 0;
    217     }
    218 
    219     /** @hide Returns {@code true} if the device is part of the group */
    220     public boolean contains(WifiP2pDevice device) {
    221         if (mOwner.equals(device) || mClients.contains(device)) return true;
    222         return false;
    223     }
    224 
    225     /** Get the list of clients currently part of the p2p group */
    226     public Collection<WifiP2pDevice> getClientList() {
    227         return Collections.unmodifiableCollection(mClients);
    228     }
    229 
    230     /** @hide */
    231     public void setPassphrase(String passphrase) {
    232         mPassphrase = passphrase;
    233     }
    234 
    235     /**
    236      * Get the passphrase of the group. This function will return a valid passphrase only
    237      * at the group owner. Legacy Wi-Fi clients will need this passphrase alongside
    238      * network name obtained from {@link #getNetworkName()} to join the group
    239      */
    240     public String getPassphrase() {
    241         return mPassphrase;
    242     }
    243 
    244     /** @hide */
    245     public void setInterface(String intf) {
    246         mInterface = intf;
    247     }
    248 
    249     /** Get the interface name on which the group is created */
    250     public String getInterface() {
    251         return mInterface;
    252     }
    253 
    254     /** @hide */
    255     public int getNetworkId() {
    256         return mNetId;
    257     }
    258 
    259     /** @hide */
    260     public void setNetworkId(int netId) {
    261         this.mNetId = netId;
    262     }
    263 
    264     public String toString() {
    265         StringBuffer sbuf = new StringBuffer();
    266         sbuf.append("network: ").append(mNetworkName);
    267         sbuf.append("\n isGO: ").append(mIsGroupOwner);
    268         sbuf.append("\n GO: ").append(mOwner);
    269         for (WifiP2pDevice client : mClients) {
    270             sbuf.append("\n Client: ").append(client);
    271         }
    272         sbuf.append("\n interface: ").append(mInterface);
    273         sbuf.append("\n networkId: ").append(mNetId);
    274         return sbuf.toString();
    275     }
    276 
    277     /** Implement the Parcelable interface */
    278     public int describeContents() {
    279         return 0;
    280     }
    281 
    282     /** copy constructor */
    283     public WifiP2pGroup(WifiP2pGroup source) {
    284         if (source != null) {
    285             mNetworkName = source.getNetworkName();
    286             mOwner = new WifiP2pDevice(source.getOwner());
    287             mIsGroupOwner = source.mIsGroupOwner;
    288             for (WifiP2pDevice d : source.getClientList()) mClients.add(d);
    289             mPassphrase = source.getPassphrase();
    290             mInterface = source.getInterface();
    291             mNetId = source.getNetworkId();
    292         }
    293     }
    294 
    295     /** Implement the Parcelable interface */
    296     public void writeToParcel(Parcel dest, int flags) {
    297         dest.writeString(mNetworkName);
    298         dest.writeParcelable(mOwner, flags);
    299         dest.writeByte(mIsGroupOwner ? (byte) 1: (byte) 0);
    300         dest.writeInt(mClients.size());
    301         for (WifiP2pDevice client : mClients) {
    302             dest.writeParcelable(client, flags);
    303         }
    304         dest.writeString(mPassphrase);
    305         dest.writeString(mInterface);
    306         dest.writeInt(mNetId);
    307     }
    308 
    309     /** Implement the Parcelable interface */
    310     public static final Creator<WifiP2pGroup> CREATOR =
    311         new Creator<WifiP2pGroup>() {
    312             public WifiP2pGroup createFromParcel(Parcel in) {
    313                 WifiP2pGroup group = new WifiP2pGroup();
    314                 group.setNetworkName(in.readString());
    315                 group.setOwner((WifiP2pDevice)in.readParcelable(null));
    316                 group.setIsGroupOwner(in.readByte() == (byte)1);
    317                 int clientCount = in.readInt();
    318                 for (int i=0; i<clientCount; i++) {
    319                     group.addClient((WifiP2pDevice) in.readParcelable(null));
    320                 }
    321                 group.setPassphrase(in.readString());
    322                 group.setInterface(in.readString());
    323                 group.setNetworkId(in.readInt());
    324                 return group;
    325             }
    326 
    327             public WifiP2pGroup[] newArray(int size) {
    328                 return new WifiP2pGroup[size];
    329             }
    330         };
    331 }
    332