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