1 /* 2 * Copyright 2024 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.google.snippet.ranging; 18 19 import static android.ranging.RangingPreference.DEVICE_ROLE_INITIATOR; 20 import static android.ranging.uwb.UwbComplexChannel.UWB_CHANNEL_9; 21 import static android.ranging.uwb.UwbComplexChannel.UWB_PREAMBLE_CODE_INDEX_11; 22 23 import android.ranging.DataNotificationConfig; 24 import android.ranging.RangingConfig; 25 import android.ranging.RangingDevice; 26 import android.ranging.RangingPreference; 27 import android.ranging.SensorFusionParams; 28 import android.ranging.SessionConfig; 29 import android.ranging.ble.cs.BleCsRangingParams; 30 import android.ranging.ble.rssi.BleRssiRangingParams; 31 import android.ranging.oob.DeviceHandle; 32 import android.ranging.oob.OobInitiatorRangingConfig; 33 import android.ranging.oob.OobResponderRangingConfig; 34 import android.ranging.raw.RawInitiatorRangingConfig; 35 import android.ranging.raw.RawRangingDevice; 36 import android.ranging.raw.RawResponderRangingConfig; 37 import android.ranging.uwb.UwbAddress; 38 import android.ranging.uwb.UwbComplexChannel; 39 import android.ranging.uwb.UwbRangingParams; 40 import android.ranging.wifi.rtt.RttRangingParams; 41 42 import com.google.android.mobly.snippet.SnippetObjectConverter; 43 44 import org.json.JSONArray; 45 import org.json.JSONException; 46 import org.json.JSONObject; 47 48 import java.lang.reflect.Type; 49 import java.time.Duration; 50 import java.util.UUID; 51 52 public class RangingPreferenceConverter implements SnippetObjectConverter { 53 54 RangingSnippet.OobTransportFactory mTransportHandleFactory; 55 RangingPreferenceConverter(RangingSnippet.OobTransportFactory transportHandleFactory)56 RangingPreferenceConverter(RangingSnippet.OobTransportFactory transportHandleFactory) { 57 mTransportHandleFactory = transportHandleFactory; 58 } 59 60 @Override serialize(Object object)61 public JSONObject serialize(Object object) { 62 throw new UnsupportedOperationException("Not implemented"); 63 } 64 65 @Override deserialize(JSONObject j, Type type)66 public RangingPreference deserialize(JSONObject j, Type type) throws JSONException { 67 if (type != RangingPreference.class) return null; 68 69 return new RangingPreference.Builder(j.getInt("device_role"), 70 getRangingParams(j.getJSONObject("ranging_params"), j.getInt("device_role"))) 71 .setSessionConfig( 72 new SessionConfig.Builder() 73 .setSensorFusionParams( 74 getSensorFusionParams( 75 j.getJSONObject("sensor_fusion_params")) 76 ) 77 .setDataNotificationConfig( 78 getDataNotificationConfig( 79 j.getBoolean("enable_range_data_notifications")) 80 ) 81 .setRangingMeasurementsLimit(j.getInt("measurement_limit")) 82 .build() 83 ) 84 .build(); 85 } 86 getRangingParams( JSONObject j, @RangingPreference.DeviceRole int role )87 private RangingConfig getRangingParams( 88 JSONObject j, @RangingPreference.DeviceRole int role 89 ) throws JSONException { 90 RangingConfig params; 91 92 if (j.getInt("session_type") == RangingConfig.RANGING_SESSION_RAW) { 93 if (role == DEVICE_ROLE_INITIATOR) { 94 params = getRawInitiatorRangingConfig(j); 95 } else { 96 params = getRawResponderRangingConfig(j); 97 } 98 } else { 99 if (role == DEVICE_ROLE_INITIATOR) { 100 params = getOobInitiatorRangingConfig(j); 101 } else { 102 params = getOobResponderRangingConfig(j); 103 } 104 } 105 106 return params; 107 } 108 getOobInitiatorRangingConfig( JSONObject j )109 private OobInitiatorRangingConfig getOobInitiatorRangingConfig( 110 JSONObject j 111 ) throws JSONException { 112 OobInitiatorRangingConfig.Builder builder = new OobInitiatorRangingConfig.Builder(); 113 JSONArray jPeers = j.getJSONArray("peer_ids"); 114 for (int i = 0; i < jPeers.length(); i++) { 115 RangingDevice device = new RangingDevice.Builder() 116 .setUuid(UUID.fromString(jPeers.getString(i))) 117 .build(); 118 builder.addDeviceHandle(new DeviceHandle.Builder( 119 device, 120 mTransportHandleFactory.createOobTransport(device) 121 ).build()); 122 } 123 return builder 124 .setFastestRangingInterval( 125 Duration.ofMillis(j.getJSONArray("ranging_interval_ms").getInt(0))) 126 .setSlowestRangingInterval( 127 Duration.ofMillis(j.getJSONArray("ranging_interval_ms").getInt(1))) 128 .setSecurityLevel(j.getInt("security_level")) 129 .setRangingMode(j.getInt("ranging_mode")) 130 .build(); 131 } 132 getOobResponderRangingConfig( JSONObject j )133 private OobResponderRangingConfig getOobResponderRangingConfig( 134 JSONObject j 135 ) throws JSONException { 136 RangingDevice device = new RangingDevice.Builder() 137 .setUuid(UUID.fromString(j.getString("peer_id"))) 138 .build(); 139 return new OobResponderRangingConfig.Builder( 140 new DeviceHandle.Builder( 141 device, mTransportHandleFactory.createOobTransport(device)).build()) 142 .build(); 143 } 144 getRawInitiatorRangingConfig( JSONObject j )145 private RawInitiatorRangingConfig getRawInitiatorRangingConfig( 146 JSONObject j 147 ) throws JSONException { 148 RawInitiatorRangingConfig.Builder builder = new RawInitiatorRangingConfig.Builder(); 149 JSONArray jPeerParams = j.getJSONArray("peer_params"); 150 for (int i = 0; i < jPeerParams.length(); i++) { 151 builder.addRawRangingDevice(getRawRangingDevice(jPeerParams.getJSONObject(i))); 152 } 153 return builder.build(); 154 } 155 getRawResponderRangingConfig( JSONObject j )156 private RawResponderRangingConfig getRawResponderRangingConfig( 157 JSONObject j 158 ) throws JSONException { 159 return new RawResponderRangingConfig.Builder() 160 .setRawRangingDevice(getRawRangingDevice(j.getJSONObject("peer_params"))) 161 .build(); 162 } 163 getRawRangingDevice(JSONObject j)164 private RawRangingDevice getRawRangingDevice(JSONObject j) throws JSONException { 165 RawRangingDevice.Builder builder = new RawRangingDevice.Builder(); 166 builder.setRangingDevice( 167 new RangingDevice.Builder() 168 .setUuid(UUID.fromString(j.getString("peer_id"))) 169 .build() 170 ); 171 if (!j.isNull("uwb_params")) { 172 builder.setUwbRangingParams(getUwbParams(j.getJSONObject("uwb_params"))); 173 } 174 if (!j.isNull("cs_params")) { 175 builder.setCsRangingParams(getCsParams(j.getJSONObject("cs_params"))); 176 } 177 if (!j.isNull("rtt_params")) { 178 builder.setRttRangingParams(getRttParams(j.getJSONObject("rtt_params"))); 179 } 180 if (!j.isNull("rssi_params")) { 181 builder.setBleRssiRangingParams(getBleRssiRangingParams( 182 j.getJSONObject("rssi_params"))); 183 } 184 return builder.build(); 185 } 186 getUwbParams(JSONObject j)187 private UwbRangingParams getUwbParams(JSONObject j) throws JSONException { 188 UwbRangingParams.Builder builder = new UwbRangingParams.Builder( 189 j.getInt("session_id"), 190 j.getInt("config_id"), 191 UwbAddress.fromBytes(toBytes(j.getJSONArray("device_address"))), 192 UwbAddress.fromBytes(toBytes(j.getJSONArray("peer_address"))) 193 ); 194 195 builder.setSubSessionId(j.getInt("sub_session_id")) 196 .setSessionKeyInfo(toBytes(j.getJSONArray("session_key_info"))) 197 .setComplexChannel( 198 new UwbComplexChannel.Builder().setChannel(UWB_CHANNEL_9) 199 .setPreambleIndex(UWB_PREAMBLE_CODE_INDEX_11).build()) 200 .setRangingUpdateRate(j.getInt("ranging_update_rate")) 201 .setSlotDuration(j.getInt("slot_duration_ms")); 202 203 if (!j.isNull("sub_session_key_info")) { 204 builder.setSubSessionKeyInfo(toBytes(j.getJSONArray("sub_session_key_info"))); 205 } 206 return builder.build(); 207 } 208 getRttParams(JSONObject j)209 private RttRangingParams getRttParams(JSONObject j) throws JSONException { 210 return new RttRangingParams.Builder(j.getString("service_name")) 211 .setPeriodicRangingHwFeatureEnabled( 212 j.getBoolean("enable_periodic_ranging_hw_feature")) 213 .setRangingUpdateRate(j.getInt("ranging_update_rate")) 214 .build(); 215 } 216 getBleRssiRangingParams(JSONObject j)217 private BleRssiRangingParams getBleRssiRangingParams(JSONObject j) throws JSONException { 218 return new BleRssiRangingParams.Builder(j.getString("peer_address")) 219 .setRangingUpdateRate(j.getInt("ranging_update_rate")) 220 .build(); 221 } 222 getCsParams(JSONObject j)223 private BleCsRangingParams getCsParams(JSONObject j) throws JSONException { 224 return new BleCsRangingParams.Builder(j.getString("peer_address")) 225 .setRangingUpdateRate(j.getInt("ranging_update_rate")) 226 .setSecurityLevel(j.getInt("security_level")) 227 .build(); 228 } 229 getSensorFusionParams(JSONObject j)230 private SensorFusionParams getSensorFusionParams(JSONObject j) throws JSONException { 231 return new SensorFusionParams.Builder() 232 .setSensorFusionEnabled(j.getBoolean("is_sensor_fusion_enabled")) 233 .build(); 234 } 235 getDataNotificationConfig(boolean enableRangeDataNotifications)236 private DataNotificationConfig getDataNotificationConfig(boolean enableRangeDataNotifications) { 237 return new DataNotificationConfig.Builder() 238 .setNotificationConfigType( 239 enableRangeDataNotifications 240 ? DataNotificationConfig.NOTIFICATION_CONFIG_ENABLE 241 : DataNotificationConfig.NOTIFICATION_CONFIG_DISABLE 242 ) 243 .build(); 244 } 245 toBytes(JSONArray jArray)246 private byte[] toBytes(JSONArray jArray) throws JSONException { 247 if (jArray == null) { 248 return null; 249 } 250 byte[] bArray = new byte[jArray.length()]; 251 for (int i = 0; i < jArray.length(); i++) { 252 bArray[i] = (byte) jArray.getInt(i); 253 } 254 return bArray; 255 } 256 } 257