1
2package com.googlecode.android_scripting.facade.wifi;
3
4import android.app.Service;
5import android.content.Context;
6import android.net.wifi.RttManager;
7import android.net.wifi.RttManager.ResponderCallback;
8import android.net.wifi.RttManager.ResponderConfig;
9import android.net.wifi.RttManager.RttCapabilities;
10import android.net.wifi.RttManager.RttListener;
11import android.net.wifi.RttManager.RttParams;
12import android.net.wifi.RttManager.RttResult;
13import android.os.Bundle;
14import android.os.Parcelable;
15
16import com.googlecode.android_scripting.facade.EventFacade;
17import com.googlecode.android_scripting.facade.FacadeManager;
18import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
19import com.googlecode.android_scripting.rpc.Rpc;
20import com.googlecode.android_scripting.rpc.RpcParameter;
21
22import org.json.JSONArray;
23import org.json.JSONException;
24import org.json.JSONObject;
25
26import java.util.ArrayList;
27import java.util.HashMap;
28import java.util.Hashtable;
29import java.util.Map;
30
31/**
32 * WifiRttManager functions.
33 */
34public class WifiRttManagerFacade extends RpcReceiver {
35    private final Service mService;
36    private final RttManager mRtt;
37    private final EventFacade mEventFacade;
38    private final Map<Integer, RttListener> mRangingListeners;
39    private final Map<Integer, RttResponderCallback> mResponderCallbacks;
40
41    public WifiRttManagerFacade(FacadeManager manager) {
42        super(manager);
43        mService = manager.getService();
44        mRtt = (RttManager) mService.getSystemService(Context.WIFI_RTT_SERVICE);
45        mEventFacade = manager.getReceiver(EventFacade.class);
46        mRangingListeners = new Hashtable<Integer, RttListener>();
47        mResponderCallbacks = new HashMap<>();
48    }
49
50    public static class RangingListener implements RttListener {
51        private static final String TAG = "WifiRttRanging";
52        private static int sCount = 0;
53        private final EventFacade mEventFacade;
54        public final int mId;
55
56        public RangingListener(EventFacade eventFacade) {
57            sCount += 1;
58            mId = sCount;
59            mEventFacade = eventFacade;
60        }
61
62        private Bundle packRttResult(RttResult result) {
63            Bundle rttResult = new Bundle();
64            rttResult.putString("BSSID", result.bssid);
65            rttResult.putInt("txRate", result.txRate);
66            rttResult.putInt("rxRate", result.rxRate);
67            rttResult.putInt("distance", result.distance);
68            rttResult.putInt("distanceStandardDeviation",
69                    result.distanceStandardDeviation);
70            rttResult.putInt("distanceSpread", result.distanceSpread);
71            rttResult.putInt("burstDuration", result.burstDuration);
72            rttResult.putLong("rtt", result.rtt);
73            rttResult.putLong("rttStandardDeviation",
74                    result.rttStandardDeviation);
75            rttResult.putLong("rttSpread", result.rttSpread);
76            rttResult.putLong("ts", result.ts);
77            rttResult.putInt("rssi", result.rssi);
78            rttResult.putInt("rssiSpread", result.rssiSpread);
79            rttResult.putInt("retryAfterDuration", result.retryAfterDuration);
80            rttResult.putInt("measurementType", result.measurementType);
81            rttResult.putInt("status", result.status);
82            rttResult.putInt("frameNumberPerBurstPeer",
83                    result.frameNumberPerBurstPeer);
84            rttResult.putInt("successMeasurementFrameNumber",
85                    result.successMeasurementFrameNumber);
86            rttResult.putInt("measurementFrameNumber",
87                    result.measurementFrameNumber);
88            rttResult.putInt("burstNumber", result.burstNumber);
89            rttResult.putInt("status", result.status);
90            return rttResult;
91        }
92
93        @Override
94        public void onSuccess(RttResult[] results) {
95            if (results == null) {
96                mEventFacade
97                        .postEvent(RangingListener.TAG + mId + "onSuccess", null);
98                return;
99            }
100            Bundle msg = new Bundle();
101            Parcelable[] resultBundles = new Parcelable[results.length];
102            for (int i = 0; i < results.length; i++) {
103                resultBundles[i] = packRttResult(results[i]);
104            }
105            msg.putParcelableArray("Results", resultBundles);
106            mEventFacade
107                    .postEvent(RangingListener.TAG + mId + "onSuccess", msg);
108        }
109
110        @Override
111        public void onFailure(int reason, String description) {
112            Bundle msg = new Bundle();
113            msg.putInt("Reason", reason);
114            msg.putString("Description", description);
115            mEventFacade
116                    .postEvent(RangingListener.TAG + mId + "onFailure", msg);
117        }
118
119        @Override
120        public void onAborted() {
121            mEventFacade.postEvent(RangingListener.TAG + mId + "onAborted",
122                    new Bundle());
123        }
124    }
125
126    /**
127     * A {@link ResponderCallback} that handles success and failures for enabling RTT responder
128     * mode.
129     */
130    private static class RttResponderCallback extends ResponderCallback {
131        private static final String TAG = "WifiRtt";
132
133        // A monotonic increasing counter for responder callback ids.
134        private static int sCount = 0;
135
136        private final int mId;
137        private final EventFacade mEventFacade;
138
139        RttResponderCallback(EventFacade eventFacade) {
140            sCount++;
141            mId = sCount;
142            mEventFacade = eventFacade;
143        }
144
145        @Override
146        public void onResponderEnabled(ResponderConfig config) {
147            Bundle bundle = new Bundle();
148            bundle.putString("macAddress", config.macAddress);
149            bundle.putInt("frequency", config.frequency);
150            bundle.putInt("centerFreq0", config.centerFreq0);
151            bundle.putInt("centerFreq1", config.centerFreq1);
152            bundle.putInt("channelWidth", config.channelWidth);
153            bundle.putInt("preamble", config.preamble);
154            mEventFacade.postEvent(TAG + mId + "onResponderEnabled", bundle);
155        }
156
157        @Override
158        public void onResponderEnableFailure(int reason) {
159            Bundle bundle = new Bundle();
160            bundle.putInt("reason", reason);
161            mEventFacade.postEvent(TAG + mId + "onResponderEnableFailure", bundle);
162        }
163    }
164
165    @Rpc(description = "Get wifi Rtt capabilities.")
166    public RttCapabilities wifiRttGetCapabilities() {
167        return mRtt.getRttCapabilities();
168    }
169
170    private RttParams parseRttParam(JSONObject j) throws JSONException {
171        RttParams result = new RttParams();
172        if (j.has("deviceType")) {
173            result.deviceType = j.getInt("deviceType");
174        }
175        if (j.has("requestType")) {
176            result.requestType = j.getInt("requestType");
177        }
178        if (j.has("bssid")) {
179            result.bssid = j.getString("bssid");
180        }
181        if (j.has("frequency")) {
182            result.frequency = j.getInt("frequency");
183        }
184        if (j.has("channelWidth")) {
185            result.channelWidth = j.getInt("channelWidth");
186        }
187        if (j.has("centerFreq0")) {
188            result.centerFreq0 = j.getInt("centerFreq0");
189        }
190        if (j.has("centerFreq1")) {
191            result.centerFreq1 = j.getInt("centerFreq1");
192        }
193        if (j.has("numberBurst")) {
194            result.numberBurst = j.getInt("numberBurst");
195        }
196        if (j.has("burstTimeout")) {
197            result.burstTimeout = j.getInt("burstTimeout");
198        }
199        if (j.has("interval")) {
200            result.interval = j.getInt("interval");
201        }
202        if (j.has("numSamplesPerBurst")) {
203            result.numSamplesPerBurst = j.getInt("numSamplesPerBurst");
204        }
205        if (j.has("numRetriesPerMeasurementFrame")) {
206            result.numRetriesPerMeasurementFrame = j
207                    .getInt("numRetriesPerMeasurementFrame");
208        }
209        if (j.has("numRetriesPerFTMR")) {
210            result.numRetriesPerFTMR = j.getInt("numRetriesPerFTMR");
211        }
212        if (j.has("LCIRequest")) {
213            result.LCIRequest = j.getBoolean("LCIRequest");
214        }
215        if (j.has("LCRRequest")) {
216            result.LCRRequest = j.getBoolean("LCRRequest");
217        }
218        if (j.has("preamble")) {
219            result.preamble = j.getInt("preamble");
220        }
221        if (j.has("bandwidth")) {
222            result.bandwidth = j.getInt("bandwidth");
223        }
224        return result;
225    }
226
227    /**
228     * Start WiFi RTT ranging using the given params. Returns the id associated with the
229     * {@link RttListener} used for ranging.
230     */
231    @Rpc(description = "Start ranging.", returns = "Id of the listener associated with the "
232            + "started ranging.")
233    public Integer wifiRttStartRanging(
234            @RpcParameter(name = "params") JSONArray params)
235            throws JSONException {
236        RttParams[] rParams = new RttParams[params.length()];
237        for (int i = 0; i < params.length(); i++) {
238            rParams[i] = parseRttParam(params.getJSONObject(i));
239        }
240        RangingListener listener = new RangingListener(mEventFacade);
241        mRangingListeners.put(listener.mId, listener);
242        mRtt.startRanging(rParams, listener);
243        return listener.mId;
244    }
245
246    /**
247     * Stop WiFi Rtt ranging for {@link RttListener} identified by the given {@code index}.
248     */
249    @Rpc(description = "Stop ranging.")
250    public void wifiRttStopRanging(@RpcParameter(name = "index") Integer index) {
251        mRtt.stopRanging(mRangingListeners.remove(index));
252    }
253
254    /**
255     * Enable WiFi RTT responder role. Returns the id associated with the {@link ResponderCallback}
256     * used for enabling responder.
257     */
258    @Rpc(description = "Enable responder", returns = "Id of the callback associated with enabling")
259    public Integer wifiRttEnableResponder() {
260        RttResponderCallback callback = new RttResponderCallback(mEventFacade);
261        mResponderCallbacks.put(callback.mId, callback);
262        mRtt.enableResponder(callback);
263        return callback.mId;
264    }
265
266    /**
267     * Disable WiFi RTT responder role for the {@link ResponderCallback} identified by the given
268     * {@code index}.
269     */
270    @Rpc(description = "Disable responder")
271    public void wifiRttDisableResponder(@RpcParameter(name = "index") Integer index) {
272        mRtt.disableResponder(mResponderCallbacks.remove(index));
273    }
274
275    @Override
276    public void shutdown() {
277        ArrayList<Integer> keys = new ArrayList<Integer>(
278                mRangingListeners.keySet());
279        for (int k : keys) {
280            wifiRttStopRanging(k);
281        }
282        for (int index : mResponderCallbacks.keySet()) {
283            wifiRttDisableResponder(index);
284        }
285    }
286}
287