1
2package com.googlecode.android_scripting.facade.wifi;
3
4import android.app.Service;
5import android.content.BroadcastReceiver;
6import android.content.Context;
7import android.content.Intent;
8import android.content.IntentFilter;
9import android.net.NetworkInfo;
10import android.net.wifi.WpsInfo;
11import android.net.wifi.p2p.WifiP2pConfig;
12import android.net.wifi.p2p.WifiP2pDevice;
13import android.net.wifi.p2p.WifiP2pDeviceList;
14import android.net.wifi.p2p.WifiP2pGroup;
15import android.net.wifi.p2p.WifiP2pGroupList;
16import android.net.wifi.p2p.WifiP2pInfo;
17import android.net.wifi.p2p.WifiP2pManager;
18import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
19import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
20import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
21import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
22import android.os.Bundle;
23import android.os.Message;
24import android.os.Messenger;
25import android.os.RemoteException;
26
27import com.android.internal.util.Protocol;
28import com.googlecode.android_scripting.Log;
29import com.googlecode.android_scripting.facade.EventFacade;
30import com.googlecode.android_scripting.facade.FacadeManager;
31import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
32import com.googlecode.android_scripting.rpc.Rpc;
33import com.googlecode.android_scripting.rpc.RpcParameter;
34
35import java.net.InetAddress;
36import java.util.ArrayList;
37import java.util.Collection;
38import java.util.HashMap;
39import java.util.List;
40import java.util.Map;
41
42import org.json.JSONException;
43import org.json.JSONObject;
44
45/**
46 * WifiP2pManager functions.
47 */
48public class WifiP2pManagerFacade extends RpcReceiver {
49
50    class WifiP2pActionListener implements WifiP2pManager.ActionListener {
51        private final EventFacade mEventFacade;
52        private final String mEventType;
53        private final String TAG;
54
55        public WifiP2pActionListener(EventFacade eventFacade, String tag) {
56            mEventType = "WifiP2p";
57            mEventFacade = eventFacade;
58            TAG = tag;
59        }
60
61        @Override
62        public void onSuccess() {
63            mEventFacade.postEvent(mEventType + TAG + "OnSuccess", null);
64        }
65
66        @Override
67        public void onFailure(int reason) {
68            Log.d("WifiActionListener  " + mEventType);
69            Bundle msg = new Bundle();
70            if (reason == WifiP2pManager.P2P_UNSUPPORTED) {
71                msg.putString("reason", "P2P_UNSUPPORTED");
72            } else if (reason == WifiP2pManager.ERROR) {
73                msg.putString("reason", "ERROR");
74            } else if (reason == WifiP2pManager.BUSY) {
75                msg.putString("reason", "BUSY");
76            } else if (reason == WifiP2pManager.NO_SERVICE_REQUESTS) {
77                msg.putString("reason", "NO_SERVICE_REQUESTS");
78            } else {
79                msg.putInt("reason", reason);
80            }
81            mEventFacade.postEvent(mEventType + TAG + "OnFailure", msg);
82        }
83    }
84
85    class WifiP2pConnectionInfoListener implements WifiP2pManager.ConnectionInfoListener {
86        private final EventFacade mEventFacade;
87        private final String mEventType;
88
89        public WifiP2pConnectionInfoListener(EventFacade eventFacade) {
90            mEventType = "WifiP2p";
91            mEventFacade = eventFacade;
92        }
93
94        @Override
95        public void onConnectionInfoAvailable(WifiP2pInfo info) {
96            Bundle msg = new Bundle();
97            msg.putBoolean("groupFormed", info.groupFormed);
98            msg.putBoolean("isGroupOwner", info.isGroupOwner);
99            InetAddress addr = info.groupOwnerAddress;
100            String hostName = null;
101            String hostAddress = null;
102            if (addr != null) {
103                hostName = addr.getHostName();
104                hostAddress = addr.getHostAddress();
105            }
106            msg.putString("groupOwnerHostName", hostName);
107            msg.putString("groupOwnerHostAddress", hostAddress);
108            mEventFacade.postEvent(mEventType + "OnConnectionInfoAvailable", msg);
109        }
110    }
111
112    class WifiP2pDnsSdServiceResponseListener implements
113            WifiP2pManager.DnsSdServiceResponseListener {
114        private final EventFacade mEventFacade;
115        private final String mEventType;
116
117        public WifiP2pDnsSdServiceResponseListener(EventFacade eventFacade) {
118            mEventType = "WifiP2p";
119            mEventFacade = eventFacade;
120        }
121
122        @Override
123        public void onDnsSdServiceAvailable(String instanceName, String registrationType,
124                WifiP2pDevice srcDevice) {
125            Bundle msg = new Bundle();
126            msg.putString("InstanceName", instanceName);
127            msg.putString("RegistrationType", registrationType);
128            msg.putString("SourceDeviceName", srcDevice.deviceName);
129            msg.putString("SourceDeviceAddress", srcDevice.deviceAddress);
130            mEventFacade.postEvent(mEventType + "OnDnsSdServiceAvailable", msg);
131        }
132    }
133
134    class WifiP2pDnsSdTxtRecordListener implements WifiP2pManager.DnsSdTxtRecordListener {
135        private final EventFacade mEventFacade;
136        private final String mEventType;
137
138        public WifiP2pDnsSdTxtRecordListener(EventFacade eventFacade) {
139            mEventType = "WifiP2p";
140            mEventFacade = eventFacade;
141        }
142
143        @Override
144        public void onDnsSdTxtRecordAvailable(String fullDomainName,
145                Map<String, String> txtRecordMap, WifiP2pDevice srcDevice) {
146            Bundle msg = new Bundle();
147            msg.putString("FullDomainName", fullDomainName);
148            Bundle txtMap = new Bundle();
149            for (String key : txtRecordMap.keySet()) {
150                txtMap.putString(key, txtRecordMap.get(key));
151            }
152            msg.putBundle("TxtRecordMap", txtMap);
153            msg.putString("SourceDeviceName", srcDevice.deviceName);
154            msg.putString("SourceDeviceAddress", srcDevice.deviceAddress);
155            mEventFacade.postEvent(mEventType + "OnDnsSdTxtRecordAvailable", msg);
156        }
157
158    }
159
160    class WifiP2pGroupInfoListener implements WifiP2pManager.GroupInfoListener {
161        private final EventFacade mEventFacade;
162        private final String mEventType;
163
164        public WifiP2pGroupInfoListener(EventFacade eventFacade) {
165            mEventType = "WifiP2p";
166            mEventFacade = eventFacade;
167        }
168
169        @Override
170        public void onGroupInfoAvailable(WifiP2pGroup group) {
171            mEventFacade.postEvent(mEventType + "OnGroupInfoAvailable", parseGroupInfo(group));
172        }
173    }
174
175    class WifiP2pPeerListListener implements WifiP2pManager.PeerListListener {
176        private final EventFacade mEventFacade;
177
178        public WifiP2pPeerListListener(EventFacade eventFacade) {
179            mEventFacade = eventFacade;
180        }
181
182        @Override
183        public void onPeersAvailable(WifiP2pDeviceList newPeers) {
184            Collection<WifiP2pDevice> devices = newPeers.getDeviceList();
185            Log.d(devices.toString());
186            if (devices.size() > 0) {
187                mP2pPeers.clear();
188                mP2pPeers.addAll(devices);
189                Bundle msg = new Bundle();
190                msg.putParcelableList("Peers", mP2pPeers);
191                mEventFacade.postEvent(mEventType + "OnPeersAvailable", msg);
192            }
193        }
194    }
195
196    class WifiP2pPersistentGroupInfoListener implements WifiP2pManager.PersistentGroupInfoListener {
197        private final EventFacade mEventFacade;
198        private final String mEventType;
199
200        public WifiP2pPersistentGroupInfoListener(EventFacade eventFacade) {
201            mEventType = "WifiP2p";
202            mEventFacade = eventFacade;
203        }
204
205        @Override
206        public void onPersistentGroupInfoAvailable(WifiP2pGroupList groups) {
207            ArrayList<Bundle> gs = new ArrayList<Bundle>();
208            for (WifiP2pGroup g : groups.getGroupList()) {
209                gs.add(parseGroupInfo(g));
210            }
211            mEventFacade.postEvent(mEventType + "OnPersistentGroupInfoAvailable", gs);
212        }
213
214    }
215
216    class WifiP2pStateChangedReceiver extends BroadcastReceiver {
217        private final EventFacade mEventFacade;
218        private final Bundle mResults;
219
220        WifiP2pStateChangedReceiver(EventFacade eventFacade) {
221            mEventFacade = eventFacade;
222            mResults = new Bundle();
223        }
224
225        @Override
226        public void onReceive(Context c, Intent intent) {
227            String action = intent.getAction();
228            if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
229                Log.d("Wifi P2p State Changed.");
230                int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, 0);
231                if (state == WifiP2pManager.WIFI_P2P_STATE_DISABLED) {
232                    Log.d("Disabled");
233                    isP2pEnabled = false;
234                } else if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
235                    Log.d("Enabled");
236                    isP2pEnabled = true;
237                }
238            } else if (action.equals(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)) {
239                Log.d("Wifi P2p Peers Changed. Requesting peers.");
240                WifiP2pDeviceList peers = intent
241                        .getParcelableExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST);
242                Log.d(peers.toString());
243                wifiP2pRequestPeers();
244            } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
245                Log.d("Wifi P2p Connection Changed.");
246                WifiP2pInfo p2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);
247                NetworkInfo networkInfo = intent
248                        .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
249                WifiP2pGroup group = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP);
250                if (networkInfo.isConnected()) {
251                    Log.d("Wifi P2p Connected.");
252                    mResults.putParcelable("P2pInfo", p2pInfo);
253                    mResults.putParcelable("Group", group);
254                    mEventFacade.postEvent(mEventType + "Connected", mResults);
255                    mResults.clear();
256                } else {
257                    mEventFacade.postEvent(mEventType + "Disconnected", null);
258                }
259            } else if (action.equals(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)) {
260                Log.d("Wifi P2p This Device Changed.");
261                WifiP2pDevice device = intent
262                        .getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
263                mResults.putParcelable("Device", device);
264                mEventFacade.postEvent(mEventType + "ThisDeviceChanged", mResults);
265                mResults.clear();
266            } else if (action.equals(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION)) {
267                Log.d("Wifi P2p Discovery Changed.");
268                int state = intent.getIntExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, 0);
269                if (state == WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED) {
270                    Log.d("discovery started.");
271                } else if (state == WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED) {
272                    Log.d("discovery stoped.");
273                }
274            }
275        }
276    }
277
278    private final static String mEventType = "WifiP2p";
279
280    private WifiP2pManager.Channel mChannel;
281    private final EventFacade mEventFacade;
282    private final WifiP2pManager mP2p;
283    private final WifiP2pStateChangedReceiver mP2pStateChangedReceiver;
284    private final Service mService;
285    private final IntentFilter mStateChangeFilter;
286    private final Map<Integer, WifiP2pServiceRequest> mServiceRequests;
287
288    private boolean isP2pEnabled;
289    private int mServiceRequestCnt = 0;
290    private WifiP2pServiceInfo mServiceInfo = null;
291    private List<WifiP2pDevice> mP2pPeers = new ArrayList<WifiP2pDevice>();
292
293    public WifiP2pManagerFacade(FacadeManager manager) {
294        super(manager);
295        mService = manager.getService();
296        mP2p = (WifiP2pManager) mService.getSystemService(Context.WIFI_P2P_SERVICE);
297        mEventFacade = manager.getReceiver(EventFacade.class);
298
299        mStateChangeFilter = new IntentFilter(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
300        mStateChangeFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
301        mStateChangeFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
302        mStateChangeFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
303        mStateChangeFilter.setPriority(999);
304
305        mP2pStateChangedReceiver = new WifiP2pStateChangedReceiver(mEventFacade);
306        mServiceRequests = new HashMap<Integer, WifiP2pServiceRequest>();
307    }
308
309    public Bundle parseGroupInfo(WifiP2pGroup group) {
310        Bundle msg = new Bundle();
311        msg.putString("Interface", group.getInterface());
312        msg.putString("NetworkName", group.getNetworkName());
313        msg.putString("Passphrase", group.getPassphrase());
314        msg.putInt("NetworkId", group.getNetworkId());
315        msg.putString("OwnerName", group.getOwner().deviceName);
316        msg.putString("OwnerAddress", group.getOwner().deviceAddress);
317        return msg;
318    }
319
320    @Override
321    public void shutdown() {
322        mService.unregisterReceiver(mP2pStateChangedReceiver);
323    }
324
325    @Rpc(description = "Accept p2p connection invitation.")
326    public void wifiP2pAcceptConnection() throws RemoteException {
327        Log.d("Accepting p2p connection.");
328        Messenger m = mP2p.getP2pStateMachineMessenger();
329        int user_accept = Protocol.BASE_WIFI_P2P_SERVICE + 2;
330        Message msg = Message.obtain();
331        msg.what = user_accept;
332        m.send(msg);
333    }
334
335    @Rpc(description = "Reject p2p connection invitation.")
336    public void wifiP2pRejectConnection() throws RemoteException {
337        Log.d("Rejecting p2p connection.");
338        Messenger m = mP2p.getP2pStateMachineMessenger();
339        int user_accept = Protocol.BASE_WIFI_P2P_SERVICE + 3;
340        Message msg = Message.obtain();
341        msg.what = user_accept;
342        m.send(msg);
343    }
344
345    @Rpc(description = "Register a local service for service discovery. One of the \"CreateXxxServiceInfo functions needs to be called first.\"")
346    public void wifiP2pAddLocalService() {
347        mP2p.addLocalService(mChannel, mServiceInfo,
348                new WifiP2pActionListener(mEventFacade, "AddLocalService"));
349    }
350
351    @Rpc(description = "Add a service discovery request.")
352    public Integer wifiP2pAddServiceRequest(
353            @RpcParameter(name = "protocolType") Integer protocolType) {
354        WifiP2pServiceRequest request = WifiP2pServiceRequest.newInstance(protocolType);
355        mServiceRequestCnt += 1;
356        mServiceRequests.put(mServiceRequestCnt, request);
357        mP2p.addServiceRequest(mChannel, request, new WifiP2pActionListener(mEventFacade,
358                "AddServiceRequest"));
359        return mServiceRequestCnt;
360    }
361
362    @Rpc(description = "Cancel any ongoing connect negotiation.")
363    public void wifiP2pCancelConnect() {
364        mP2p.cancelConnect(mChannel, new WifiP2pActionListener(mEventFacade, "CancelConnect"));
365    }
366
367    @Rpc(description = "Clear all registered local services of service discovery.")
368    public void wifiP2pClearLocalServices() {
369        mP2p.clearLocalServices(mChannel,
370                new WifiP2pActionListener(mEventFacade, "ClearLocalServices"));
371    }
372
373    @Rpc(description = "Clear all registered service discovery requests.")
374    public void wifiP2pClearServiceRequests() {
375        mP2p.clearServiceRequests(mChannel,
376                new WifiP2pActionListener(mEventFacade, "ClearServiceRequests"));
377    }
378
379    @Rpc(description = "Connects to a discovered wifi p2p device.")
380    public void wifiP2pConnect(@RpcParameter(name = "deviceId") String deviceId) {
381        for (WifiP2pDevice d : mP2pPeers) {
382            if (wifiP2pDeviceMatches(d, deviceId)) {
383                WifiP2pConfig config = new WifiP2pConfig();
384                config.deviceAddress = d.deviceAddress;
385                config.wps.setup = WpsInfo.PBC;
386                mP2p.connect(mChannel, config,
387                        new WifiP2pActionListener(mEventFacade, "Connect"));
388            }
389        }
390    }
391
392    @Rpc(description = "Create a Bonjour service info object to be used for wifiP2pAddLocalService.")
393    public void wifiP2pCreateBonjourServiceInfo(
394            @RpcParameter(name = "instanceName") String instanceName,
395            @RpcParameter(name = "serviceType") String serviceType,
396            @RpcParameter(name = "txtMap") JSONObject txtMap) throws JSONException {
397        Map<String, String> map = new HashMap<String, String>();
398        for (String key : txtMap.keySet()) {
399            map.put(key, txtMap.getString(key));
400        }
401        mServiceInfo = WifiP2pDnsSdServiceInfo.newInstance(instanceName, serviceType, map);
402    }
403
404    @Rpc(description = "Create a wifi p2p group.")
405    public void wifiP2pCreateGroup() {
406        mP2p.createGroup(mChannel, new WifiP2pActionListener(mEventFacade, "CreatGroup"));
407    }
408
409    @Rpc(description = "Create a Upnp service info object to be used for wifiP2pAddLocalService.")
410    public void wifiP2pCreateUpnpServiceInfo(
411            @RpcParameter(name = "uuid") String uuid,
412            @RpcParameter(name = "device") String device,
413            @RpcParameter(name = "services") List<String> services) {
414        mServiceInfo = WifiP2pUpnpServiceInfo.newInstance(uuid, device, services);
415    }
416
417    @Rpc(description = "Delete a stored persistent group from the system settings.")
418    public void wifiP2pDeletePersistentGroup(@RpcParameter(name = "netId") Integer netId) {
419        mP2p.deletePersistentGroup(mChannel, netId,
420                new WifiP2pActionListener(mEventFacade, "DeletePersistentGroup"));
421    }
422
423    private boolean wifiP2pDeviceMatches(WifiP2pDevice d, String deviceId) {
424        return d.deviceName.equals(deviceId) || d.deviceAddress.equals(deviceId);
425    }
426
427    @Rpc(description = "Start peers discovery for wifi p2p.")
428    public void wifiP2pDiscoverPeers() {
429        mP2p.discoverPeers(mChannel, new WifiP2pActionListener(mEventFacade, "DiscoverPeers"));
430    }
431
432    @Rpc(description = "Initiate service discovery.")
433    public void wifiP2pDiscoverServices() {
434        mP2p.discoverServices(mChannel,
435                new WifiP2pActionListener(mEventFacade, "DiscoverServices"));
436    }
437
438    @Rpc(description = "Initialize wifi p2p. Must be called before any other p2p functions.")
439    public void wifiP2pInitialize() {
440        mService.registerReceiver(mP2pStateChangedReceiver, mStateChangeFilter);
441        mChannel = mP2p.initialize(mService, mService.getMainLooper(), null);
442    }
443
444    @Rpc(description = "Returns true if wifi p2p is enabled, false otherwise.")
445    public Boolean wifiP2pIsEnabled() {
446        return isP2pEnabled;
447    }
448
449    @Rpc(description = "Remove the current p2p group.")
450    public void wifiP2pRemoveGroup() {
451        mP2p.removeGroup(mChannel, new WifiP2pActionListener(mEventFacade, "RemoveGroup"));
452    }
453
454    @Rpc(description = "Remove a registered local service added with wifiP2pAddLocalService.")
455    public void wifiP2pRemoveLocalService() {
456        mP2p.removeLocalService(mChannel, mServiceInfo,
457                new WifiP2pActionListener(mEventFacade, "RemoveLocalService"));
458    }
459
460    @Rpc(description = "Remove a service discovery request.")
461    public void wifiP2pRemoveServiceRequest(@RpcParameter(name = "index") Integer index) {
462        mP2p.removeServiceRequest(mChannel, mServiceRequests.remove(index),
463                new WifiP2pActionListener(mEventFacade, "RemoveServiceRequest"));
464    }
465
466    @Rpc(description = "Request device connection info.")
467    public void wifiP2pRequestConnectionInfo() {
468        mP2p.requestConnectionInfo(mChannel, new WifiP2pConnectionInfoListener(mEventFacade));
469    }
470
471    @Rpc(description = "Create a wifi p2p group.")
472    public void wifiP2pRequestGroupInfo() {
473        mP2p.requestGroupInfo(mChannel, new WifiP2pGroupInfoListener(mEventFacade));
474    }
475
476    @Rpc(description = "Request peers that are discovered for wifi p2p.")
477    public void wifiP2pRequestPeers() {
478        mP2p.requestPeers(mChannel, new WifiP2pPeerListListener(mEventFacade));
479    }
480
481    @Rpc(description = "Request a list of all the persistent p2p groups stored in system.")
482    public void wifiP2pRequestPersistentGroupInfo() {
483        mP2p.requestPersistentGroupInfo(mChannel,
484                new WifiP2pPersistentGroupInfoListener(mEventFacade));
485    }
486
487    @Rpc(description = "Set p2p device name.")
488    public void wifiP2pSetDeviceName(@RpcParameter(name = "devName") String devName) {
489        mP2p.setDeviceName(mChannel, devName,
490                new WifiP2pActionListener(mEventFacade, "SetDeviceName"));
491    }
492
493    @Rpc(description = "Register a callback to be invoked on receiving Bonjour service discovery response.")
494    public void wifiP2pSetDnsSdResponseListeners() {
495        mP2p.setDnsSdResponseListeners(mChannel,
496                new WifiP2pDnsSdServiceResponseListener(mEventFacade),
497                new WifiP2pDnsSdTxtRecordListener(mEventFacade));
498    }
499
500    @Rpc(description = "Stop an ongoing peer discovery.")
501    public void wifiP2pStopPeerDiscovery() {
502        mP2p.stopPeerDiscovery(mChannel,
503                new WifiP2pActionListener(mEventFacade, "StopPeerDiscovery"));
504    }
505
506}
507