1 /*
2  * Copyright (C) 2012 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 package android.net.wifi.p2p;
17 
18 import android.annotation.NonNull;
19 import android.annotation.SystemApi;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.util.LruCache;
24 
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.List;
28 import java.util.Map;
29 
30 
31 /**
32  * A class representing a Wi-Fi P2p group list
33  *
34  * {@see WifiP2pManager}
35  * @hide
36  */
37 @SystemApi
38 public final class WifiP2pGroupList implements Parcelable {
39 
40     private static final int CREDENTIAL_MAX_NUM             =   32;
41 
42     @UnsupportedAppUsage
43     private final LruCache<Integer, WifiP2pGroup> mGroups;
44     private final GroupDeleteListener mListener;
45 
46     private boolean isClearCalled = false;
47 
48     /** @hide */
49     public interface GroupDeleteListener {
onDeleteGroup(int netId)50         public void onDeleteGroup(int netId);
51     }
52 
53     /** @hide */
WifiP2pGroupList()54     public WifiP2pGroupList() {
55         this(null, null);
56     }
57 
58     /** @hide */
59     @UnsupportedAppUsage
WifiP2pGroupList(WifiP2pGroupList source, GroupDeleteListener listener)60     public WifiP2pGroupList(WifiP2pGroupList source, GroupDeleteListener listener) {
61         mListener = listener;
62         mGroups = new LruCache<Integer, WifiP2pGroup>(CREDENTIAL_MAX_NUM) {
63             @Override
64             protected void entryRemoved(boolean evicted, Integer netId,
65                     WifiP2pGroup oldValue, WifiP2pGroup newValue) {
66                 if (mListener != null && !isClearCalled) {
67                     mListener.onDeleteGroup(oldValue.getNetworkId());
68                 }
69             }
70         };
71 
72         if (source != null) {
73             for (Map.Entry<Integer, WifiP2pGroup> item : source.mGroups.snapshot().entrySet()) {
74                 mGroups.put(item.getKey(), item.getValue());
75             }
76         }
77     }
78 
79     /**
80      * Get the list of P2P groups.
81      */
82     @NonNull
getGroupList()83     public List<WifiP2pGroup> getGroupList() {
84         return new ArrayList<>(mGroups.snapshot().values());
85     }
86 
87     /**
88      * Add the specified group to this group list.
89      *
90      * @param group
91      * @hide
92      */
add(WifiP2pGroup group)93     public void add(WifiP2pGroup group) {
94         mGroups.put(group.getNetworkId(), group);
95     }
96 
97     /**
98      * Remove the group with the specified network id from this group list.
99      *
100      * @param netId
101      * @hide
102      */
remove(int netId)103     public void remove(int netId) {
104         mGroups.remove(netId);
105     }
106 
107     /**
108      * Remove the group with the specified device address from this group list.
109      *
110      * @param deviceAddress
111      */
remove(String deviceAddress)112     void remove(String deviceAddress) {
113         remove(getNetworkId(deviceAddress));
114     }
115 
116     /**
117      * Clear the group.
118      * @hide
119      */
clear()120     public boolean clear() {
121         if (mGroups.size() == 0) return false;
122         isClearCalled = true;
123         mGroups.evictAll();
124         isClearCalled = false;
125         return true;
126     }
127 
128     /**
129      * Return the network id of the group owner profile with the specified p2p device
130      * address.
131      * If more than one persistent group of the same address is present in the list,
132      * return the first one.
133      *
134      * @param deviceAddress p2p device address.
135      * @return the network id. if not found, return -1.
136      * @hide
137      */
getNetworkId(String deviceAddress)138     public int getNetworkId(String deviceAddress) {
139         if (deviceAddress == null) return -1;
140 
141         final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
142         for (WifiP2pGroup grp : groups) {
143             WifiP2pDevice groupOwner = grp.getOwner();
144             if (groupOwner == null) {
145                 continue;
146             }
147             if (deviceAddress.equalsIgnoreCase(groupOwner.deviceAddress)) {
148                 // update cache ordered.
149                 mGroups.get(grp.getNetworkId());
150                 return grp.getNetworkId();
151             }
152         }
153         return -1;
154     }
155 
156     /**
157      * Return the network id of the group with the specified p2p device address
158      * and the ssid.
159      *
160      * @param deviceAddress p2p device address.
161      * @param ssid ssid.
162      * @return the network id. if not found, return -1.
163      * @hide
164      */
getNetworkId(String deviceAddress, String ssid)165     public int getNetworkId(String deviceAddress, String ssid) {
166         if (deviceAddress == null || ssid == null) {
167             return -1;
168         }
169 
170         final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
171         for (WifiP2pGroup grp : groups) {
172             WifiP2pDevice groupOwner = grp.getOwner();
173             if (groupOwner == null) {
174                 continue;
175             }
176             if (deviceAddress.equalsIgnoreCase(groupOwner.deviceAddress)
177                     && ssid.equals(grp.getNetworkName())) {
178                 // update cache ordered.
179                 mGroups.get(grp.getNetworkId());
180                 return grp.getNetworkId();
181             }
182         }
183 
184         return -1;
185     }
186 
187     /**
188      * Return the group owner address of the group with the specified network id
189      *
190      * @param netId network id.
191      * @return the address. if not found, return null.
192      * @hide
193      */
getOwnerAddr(int netId)194     public String getOwnerAddr(int netId) {
195         WifiP2pGroup grp = mGroups.get(netId);
196         if (grp == null) {
197             return null;
198         }
199         WifiP2pDevice groupOwner = grp.getOwner();
200         if (groupOwner == null) {
201             return null;
202         }
203         return groupOwner.deviceAddress;
204     }
205 
206     /**
207      * Return true if this group list contains the specified network id.
208      * This function does NOT update LRU information.
209      * It means the internal queue is NOT reordered.
210      *
211      * @param netId network id.
212      * @return true if the specified network id is present in this group list.
213      * @hide
214      */
contains(int netId)215     public boolean contains(int netId) {
216         final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
217         for (WifiP2pGroup grp: groups) {
218             if (netId == grp.getNetworkId()) {
219                 return true;
220             }
221         }
222         return false;
223     }
224 
225     @Override
toString()226     public String toString() {
227         StringBuffer sbuf = new StringBuffer();
228 
229         final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
230         for (WifiP2pGroup grp: groups) {
231             sbuf.append(grp).append("\n");
232         }
233         return sbuf.toString();
234     }
235 
236     /** Implement the Parcelable interface */
237     @Override
describeContents()238     public int describeContents() {
239         return 0;
240     }
241 
242     /** Implement the Parcelable interface */
243     @Override
writeToParcel(@onNull Parcel dest, int flags)244     public void writeToParcel(@NonNull Parcel dest, int flags) {
245         final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
246         dest.writeInt(groups.size());
247         for(WifiP2pGroup group : groups) {
248             dest.writeParcelable(group, flags);
249         }
250     }
251 
252     /** Implement the Parcelable interface */
253     public static final @NonNull Creator<WifiP2pGroupList> CREATOR =
254         new Creator<WifiP2pGroupList>() {
255             public WifiP2pGroupList createFromParcel(Parcel in) {
256                 WifiP2pGroupList grpList = new WifiP2pGroupList();
257 
258                 int deviceCount = in.readInt();
259                 for (int i = 0; i < deviceCount; i++) {
260                     grpList.add((WifiP2pGroup)in.readParcelable(null));
261                 }
262                 return grpList;
263             }
264 
265             public WifiP2pGroupList[] newArray(int size) {
266                 return new WifiP2pGroupList[size];
267             }
268         };
269 }
270