• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 com.googlecode.android_scripting.facade.wifi;
18 
19 import android.app.Service;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.pm.PackageManager;
25 import android.net.MacAddress;
26 import android.net.wifi.aware.PeerHandle;
27 import android.net.wifi.rtt.RangingRequest;
28 import android.net.wifi.rtt.RangingResult;
29 import android.net.wifi.rtt.RangingResultCallback;
30 import android.net.wifi.rtt.WifiRttManager;
31 import android.os.Bundle;
32 import android.os.Parcelable;
33 import android.os.RemoteException;
34 import android.os.WorkSource;
35 
36 import com.android.internal.annotations.GuardedBy;
37 
38 import libcore.util.HexEncoding;
39 
40 import com.googlecode.android_scripting.facade.EventFacade;
41 import com.googlecode.android_scripting.facade.FacadeManager;
42 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
43 import com.googlecode.android_scripting.rpc.Rpc;
44 import com.googlecode.android_scripting.rpc.RpcOptional;
45 import com.googlecode.android_scripting.rpc.RpcParameter;
46 
47 import org.json.JSONArray;
48 import org.json.JSONException;
49 
50 import java.util.List;
51 
52 /**
53  * Facade for RTTv2 manager.
54  */
55 public class WifiRtt2ManagerFacade extends RpcReceiver {
56     private final Service mService;
57     private final EventFacade mEventFacade;
58     private final StateChangedReceiver mStateChangedReceiver;
59 
60     private final Object mLock = new Object(); // lock access to the following vars
61 
62     @GuardedBy("mLock")
63     private WifiRttManager mMgr;
64 
65     @GuardedBy("mLock")
66     private int mNextRangingResultCallbackId = 1;
67 
WifiRtt2ManagerFacade(FacadeManager manager)68     public WifiRtt2ManagerFacade(FacadeManager manager) {
69         super(manager);
70         mService = manager.getService();
71         mEventFacade = manager.getReceiver(EventFacade.class);
72 
73         mMgr = (WifiRttManager) mService.getSystemService(Context.WIFI_RTT_RANGING_SERVICE);
74 
75         mStateChangedReceiver = new StateChangedReceiver();
76         IntentFilter filter = new IntentFilter(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED);
77         mService.registerReceiver(mStateChangedReceiver, filter);
78     }
79 
80     @Override
shutdown()81     public void shutdown() {
82         mService.unregisterReceiver(mStateChangedReceiver);
83     }
84 
85     @Rpc(description = "Does the device support the Wi-Fi RTT feature?")
doesDeviceSupportWifiRttFeature()86     public Boolean doesDeviceSupportWifiRttFeature() {
87         return mService.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);
88     }
89 
90     @Rpc(description = "Is Wi-Fi RTT Usage Enabled?")
wifiIsRttAvailable()91     public Boolean wifiIsRttAvailable() throws RemoteException {
92         synchronized (mLock) {
93             return mMgr.isAvailable();
94         }
95     }
96 
97     @Rpc(description = "The maximum number of peers permitted in a single RTT request")
wifiRttMaxPeersInRequest()98     public Integer wifiRttMaxPeersInRequest() {
99       return RangingRequest.getMaxPeers();
100     }
101 
102     /**
103      * Start Wi-Fi RTT ranging to an Acccess Point using the given scan results. Returns the id
104      * associated with the listener used for ranging. The ranging result event will be decorated
105      * with the listener id.
106      */
107     @Rpc(description = "Start ranging to an Access Points.", returns = "Id of the listener "
108             + "associated with the started ranging.")
wifiRttStartRangingToAccessPoints( @pcParametername = "scanResults") JSONArray scanResults, @RpcParameter(name = "uidsOverride", description = "Overrides for the UID") @RpcOptional JSONArray uidsOverride)109     public Integer wifiRttStartRangingToAccessPoints(
110             @RpcParameter(name = "scanResults") JSONArray scanResults,
111             @RpcParameter(name = "uidsOverride", description = "Overrides for the UID")
112                 @RpcOptional JSONArray uidsOverride) throws JSONException {
113         synchronized (mLock) {
114             int id = mNextRangingResultCallbackId++;
115             RangingResultCallback callback = new RangingResultCallbackFacade(id);
116             mMgr.startRanging(getWorkSource(uidsOverride),
117                     new RangingRequest.Builder().addAccessPoints(
118                             WifiJsonParser.getScanResults(scanResults)).build(),
119                     mService.getMainExecutor(), callback);
120             return id;
121         }
122     }
123 
124     @Rpc(description = "Start ranging to an Aware peer.", returns = "Id of the listener "
125             + "associated with the started ranging.")
wifiRttStartRangingToAwarePeerMac( @pcParametername = "peerMac") String peerMac, @RpcParameter(name = "uidsOverride", description = "Overrides for the UID") @RpcOptional JSONArray uidsOverride)126     public Integer wifiRttStartRangingToAwarePeerMac(
127             @RpcParameter(name = "peerMac") String peerMac,
128             @RpcParameter(name = "uidsOverride", description = "Overrides for the UID")
129             @RpcOptional JSONArray uidsOverride) throws JSONException {
130         synchronized (mLock) {
131             int id = mNextRangingResultCallbackId++;
132             RangingResultCallback callback = new RangingResultCallbackFacade(id);
133             byte[] peerMacBytes = HexEncoding.decode(peerMac); // since Aware returns string w/o ":"
134             mMgr.startRanging(getWorkSource(uidsOverride),
135                     new RangingRequest.Builder().addWifiAwarePeer(
136                             MacAddress.fromBytes(peerMacBytes)).build(), mService.getMainExecutor(),
137                     callback);
138             return id;
139         }
140     }
141 
142     @Rpc(description = "Start ranging to an Aware peer.", returns = "Id of the listener "
143             + "associated with the started ranging.")
wifiRttStartRangingToAwarePeerId( @pcParametername = "peer ID") Integer peerId, @RpcParameter(name = "uidsOverride", description = "Overrides for the UID") @RpcOptional JSONArray uidsOverride)144     public Integer wifiRttStartRangingToAwarePeerId(
145             @RpcParameter(name = "peer ID") Integer peerId,
146             @RpcParameter(name = "uidsOverride", description = "Overrides for the UID")
147             @RpcOptional JSONArray uidsOverride) throws JSONException {
148         synchronized (mLock) {
149             int id = mNextRangingResultCallbackId++;
150             RangingResultCallback callback = new RangingResultCallbackFacade(id);
151             mMgr.startRanging(getWorkSource(uidsOverride),
152                     new RangingRequest.Builder().addWifiAwarePeer(
153                             new PeerHandle(peerId)).build(), mService.getMainExecutor(), callback);
154             return id;
155         }
156     }
157 
158     @Rpc(description = "Cancel ranging requests for the specified UIDs")
wifiRttCancelRanging(@pcParametername = "uids", description = "List of UIDs") @pcOptional JSONArray uids)159     public void wifiRttCancelRanging(@RpcParameter(name = "uids", description = "List of UIDs")
160         @RpcOptional JSONArray uids) throws JSONException {
161         synchronized (mLock) {
162             mMgr.cancelRanging(getWorkSource(uids));
163         }
164     }
165 
166     private class RangingResultCallbackFacade extends RangingResultCallback {
167         private int mCallbackId;
168 
RangingResultCallbackFacade(int callbackId)169         RangingResultCallbackFacade(int callbackId) {
170             mCallbackId = callbackId;
171         }
172 
173         @Override
onRangingFailure(int status)174         public void onRangingFailure(int status) {
175             Bundle msg = new Bundle();
176             msg.putInt("status", status);
177             mEventFacade.postEvent("WifiRttRangingFailure_" + mCallbackId, msg);
178         }
179 
180         @Override
onRangingResults(List<RangingResult> results)181         public void onRangingResults(List<RangingResult> results) {
182             Bundle msg = new Bundle();
183             Parcelable[] resultBundles = new Parcelable[results.size()];
184             for (int i = 0; i < results.size(); i++) {
185                 resultBundles[i] = packRttResult(results.get(i));
186             }
187             msg.putParcelableArray("Results", resultBundles);
188             mEventFacade.postEvent("WifiRttRangingResults_" + mCallbackId, msg);
189         }
190     }
191 
192     // conversion utilities
packRttResult(RangingResult result)193     private static Bundle packRttResult(RangingResult result) {
194         Bundle bundle = new Bundle();
195         bundle.putInt("status", result.getStatus());
196         if (result.getStatus() == RangingResult.STATUS_SUCCESS) { // only valid on SUCCESS
197             bundle.putInt("distanceMm", result.getDistanceMm());
198             bundle.putInt("distanceStdDevMm", result.getDistanceStdDevMm());
199             bundle.putInt("rssi", result.getRssi());
200             bundle.putInt("numAttemptedMeasurements", result.getNumAttemptedMeasurements());
201             bundle.putInt("numSuccessfulMeasurements", result.getNumSuccessfulMeasurements());
202             bundle.putByteArray("lci", result.getLci());
203             bundle.putByteArray("lcr", result.getLcr());
204             bundle.putLong("timestamp", result.getRangingTimestampMillis());
205         }
206         if (result.getPeerHandle() != null) {
207             bundle.putInt("peerId", result.getPeerHandle().peerId);
208         }
209         if (result.getMacAddress() != null) {
210             bundle.putByteArray("mac", result.getMacAddress().toByteArray());
211             bundle.putString("macAsString", result.getMacAddress().toString());
212         }
213         return bundle;
214     }
215 
getWorkSource(JSONArray uids)216     private static WorkSource getWorkSource(JSONArray uids) throws JSONException {
217         if (uids == null) {
218             return null;
219         }
220         WorkSource ws = new WorkSource();
221         for (int i = 0; i < uids.length(); ++i) {
222             ws.add(uids.getInt(i));
223         }
224         return ws;
225     }
226 
227     class StateChangedReceiver extends BroadcastReceiver {
228         @Override
onReceive(Context c, Intent intent)229         public void onReceive(Context c, Intent intent) {
230             boolean isAvailable = mMgr.isAvailable();
231             mEventFacade.postEvent(isAvailable ? "WifiRttAvailable" : "WifiRttNotAvailable",
232                     new Bundle());
233         }
234     }
235 }
236