1/*
2 * Copyright (C) 2016 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package com.googlecode.android_scripting.jsonrpc;
18
19import java.io.IOException;
20import java.net.HttpURLConnection;
21import java.net.InetAddress;
22import java.net.InetSocketAddress;
23import java.net.URL;
24import java.security.PrivateKey;
25import java.security.cert.CertificateEncodingException;
26import java.security.cert.X509Certificate;
27import java.util.ArrayList;
28import java.util.Collection;
29import java.util.List;
30import java.util.Map;
31import java.util.Map.Entry;
32import java.util.Set;
33
34import org.apache.commons.codec.binary.Base64Codec;
35import org.json.JSONArray;
36import org.json.JSONException;
37import org.json.JSONObject;
38
39import android.bluetooth.BluetoothDevice;
40import android.bluetooth.BluetoothGattCharacteristic;
41import android.bluetooth.BluetoothGattDescriptor;
42import android.bluetooth.BluetoothGattService;
43import android.bluetooth.le.AdvertiseSettings;
44import android.content.ComponentName;
45import android.content.Intent;
46import android.graphics.Point;
47import android.location.Address;
48import android.location.Location;
49import android.net.DhcpInfo;
50import android.net.Network;
51import android.net.NetworkInfo;
52import android.net.Uri;
53import android.net.wifi.RttManager.RttCapabilities;
54import android.net.wifi.ScanResult;
55import android.net.wifi.WifiActivityEnergyInfo;
56import android.net.wifi.WifiChannel;
57import android.net.wifi.WifiConfiguration;
58import android.net.wifi.WifiEnterpriseConfig;
59import android.net.wifi.WifiInfo;
60import android.net.wifi.WifiScanner.ScanData;
61import android.net.wifi.p2p.WifiP2pDevice;
62import android.net.wifi.p2p.WifiP2pGroup;
63import android.net.wifi.p2p.WifiP2pInfo;
64import android.os.Bundle;
65import android.os.ParcelUuid;
66import android.telecom.Call;
67import android.telecom.CallAudioState;
68import android.telecom.PhoneAccount;
69import android.telecom.PhoneAccountHandle;
70import android.telecom.VideoProfile;
71import android.telecom.VideoProfile.CameraCapabilities;
72import android.telephony.CellIdentityCdma;
73import android.telephony.CellIdentityGsm;
74import android.telephony.CellIdentityLte;
75import android.telephony.CellIdentityWcdma;
76import android.telephony.CellInfoCdma;
77import android.telephony.CellInfoGsm;
78import android.telephony.CellInfoLte;
79import android.telephony.CellInfoWcdma;
80import android.telephony.CellLocation;
81import android.telephony.CellSignalStrengthCdma;
82import android.telephony.CellSignalStrengthGsm;
83import android.telephony.CellSignalStrengthLte;
84import android.telephony.CellSignalStrengthWcdma;
85import android.telephony.ModemActivityInfo;
86import android.telephony.NeighboringCellInfo;
87import android.telephony.SmsMessage;
88import android.telephony.SignalStrength;
89import android.telephony.SubscriptionInfo;
90import android.telephony.gsm.GsmCellLocation;
91import android.telephony.VoLteServiceState;
92import android.util.Base64;
93import android.util.DisplayMetrics;
94import android.util.SparseArray;
95
96import com.googlecode.android_scripting.ConvertUtils;
97import com.googlecode.android_scripting.Log;
98import com.googlecode.android_scripting.event.Event;
99//FIXME: Refactor classes, constants and conversions out of here
100import com.googlecode.android_scripting.facade.telephony.InCallServiceImpl;
101import com.googlecode.android_scripting.facade.telephony.TelephonyUtils;
102import com.googlecode.android_scripting.facade.telephony.TelephonyConstants;
103
104public class JsonBuilder {
105
106    @SuppressWarnings("unchecked")
107    public static Object build(Object data) throws JSONException {
108        if (data == null) {
109            return JSONObject.NULL;
110        }
111        if (data instanceof Integer) {
112            return data;
113        }
114        if (data instanceof Float) {
115            return data;
116        }
117        if (data instanceof Double) {
118            return data;
119        }
120        if (data instanceof Long) {
121            return data;
122        }
123        if (data instanceof String) {
124            return data;
125        }
126        if (data instanceof Boolean) {
127            return data;
128        }
129        if (data instanceof JsonSerializable) {
130            return ((JsonSerializable)data).toJSON();
131        }
132        if (data instanceof JSONObject) {
133            return data;
134        }
135        if (data instanceof JSONArray) {
136            return data;
137        }
138        if (data instanceof Set<?>) {
139            List<Object> items = new ArrayList<Object>((Set<?>) data);
140            return buildJsonList(items);
141        }
142        if (data instanceof Collection<?>) {
143            List<Object> items = new ArrayList<Object>((Collection<?>) data);
144            return buildJsonList(items);
145        }
146        if (data instanceof List<?>) {
147            return buildJsonList((List<?>) data);
148        }
149        if (data instanceof Address) {
150            return buildJsonAddress((Address) data);
151        }
152        if (data instanceof CallAudioState) {
153            return buildJsonAudioState((CallAudioState) data);
154        }
155        if (data instanceof Location) {
156            return buildJsonLocation((Location) data);
157        }
158        if (data instanceof Bundle) {
159            return buildJsonBundle((Bundle) data);
160        }
161        if (data instanceof Intent) {
162            return buildJsonIntent((Intent) data);
163        }
164        if (data instanceof Event) {
165            return buildJsonEvent((Event) data);
166        }
167        if (data instanceof Map<?, ?>) {
168            // TODO(damonkohler): I would like to make this a checked cast if
169            // possible.
170            return buildJsonMap((Map<String, ?>) data);
171        }
172        if (data instanceof ParcelUuid) {
173            return data.toString();
174        }
175        if (data instanceof ScanResult) {
176            return buildJsonScanResult((ScanResult) data);
177        }
178        if (data instanceof ScanData) {
179            return buildJsonScanData((ScanData) data);
180        }
181        if (data instanceof android.bluetooth.le.ScanResult) {
182            return buildJsonBleScanResult((android.bluetooth.le.ScanResult) data);
183        }
184        if (data instanceof AdvertiseSettings) {
185            return buildJsonBleAdvertiseSettings((AdvertiseSettings) data);
186        }
187        if (data instanceof BluetoothGattService) {
188            return buildJsonBluetoothGattService((BluetoothGattService) data);
189        }
190        if (data instanceof BluetoothGattCharacteristic) {
191            return buildJsonBluetoothGattCharacteristic((BluetoothGattCharacteristic) data);
192        }
193        if (data instanceof BluetoothGattDescriptor) {
194            return buildJsonBluetoothGattDescriptor((BluetoothGattDescriptor) data);
195        }
196        if (data instanceof BluetoothDevice) {
197            return buildJsonBluetoothDevice((BluetoothDevice) data);
198        }
199        if (data instanceof CellLocation) {
200            return buildJsonCellLocation((CellLocation) data);
201        }
202        if (data instanceof WifiInfo) {
203            return buildJsonWifiInfo((WifiInfo) data);
204        }
205        if (data instanceof NeighboringCellInfo) {
206            return buildNeighboringCellInfo((NeighboringCellInfo) data);
207        }
208        if (data instanceof Network) {
209            return buildNetwork((Network) data);
210        }
211        if (data instanceof NetworkInfo) {
212            return buildNetworkInfo((NetworkInfo) data);
213        }
214        if (data instanceof HttpURLConnection) {
215            return buildHttpURLConnection((HttpURLConnection) data);
216        }
217        if (data instanceof InetSocketAddress) {
218            return buildInetSocketAddress((InetSocketAddress) data);
219        }
220        if (data instanceof InetAddress) {
221            return buildInetAddress((InetAddress) data);
222        }
223        if (data instanceof URL) {
224            return buildURL((URL) data);
225        }
226        if (data instanceof Point) {
227            return buildPoint((Point) data);
228        }
229        if (data instanceof SmsMessage) {
230            return buildSmsMessage((SmsMessage) data);
231        }
232        if (data instanceof PhoneAccount) {
233            return buildPhoneAccount((PhoneAccount) data);
234        }
235        if (data instanceof PhoneAccountHandle) {
236            return buildPhoneAccountHandle((PhoneAccountHandle) data);
237        }
238        if (data instanceof SubscriptionInfo) {
239            return buildSubscriptionInfoRecord((SubscriptionInfo) data);
240        }
241        if (data instanceof DhcpInfo) {
242            return buildDhcpInfo((DhcpInfo) data);
243        }
244        if (data instanceof DisplayMetrics) {
245            return buildDisplayMetrics((DisplayMetrics) data);
246        }
247        if (data instanceof RttCapabilities) {
248            return buildRttCapabilities((RttCapabilities) data);
249        }
250        if (data instanceof WifiActivityEnergyInfo) {
251            return buildWifiActivityEnergyInfo((WifiActivityEnergyInfo) data);
252        }
253        if (data instanceof WifiChannel) {
254            return buildWifiChannel((WifiChannel) data);
255        }
256        if (data instanceof WifiConfiguration) {
257            return buildWifiConfiguration((WifiConfiguration) data);
258        }
259        if (data instanceof WifiP2pDevice) {
260            return buildWifiP2pDevice((WifiP2pDevice) data);
261        }
262        if (data instanceof WifiP2pInfo) {
263            return buildWifiP2pInfo((WifiP2pInfo) data);
264        }
265        if (data instanceof WifiP2pGroup) {
266            return buildWifiP2pGroup((WifiP2pGroup) data);
267        }
268        if (data instanceof byte[]) {
269            JSONArray result = new JSONArray();
270            for (byte b : (byte[]) data) {
271                result.put(b&0xFF);
272            }
273            return result;
274        }
275        if (data instanceof Object[]) {
276            return buildJSONArray((Object[]) data);
277        }
278        if (data instanceof CellInfoLte) {
279            return buildCellInfoLte((CellInfoLte) data);
280        }
281        if (data instanceof CellInfoWcdma) {
282            return buildCellInfoWcdma((CellInfoWcdma) data);
283        }
284        if (data instanceof CellInfoGsm) {
285            return buildCellInfoGsm((CellInfoGsm) data);
286        }
287        if (data instanceof CellInfoCdma) {
288            return buildCellInfoCdma((CellInfoCdma) data);
289        }
290        if (data instanceof Call) {
291            return buildCall((Call) data);
292        }
293        if (data instanceof Call.Details) {
294            return buildCallDetails((Call.Details) data);
295        }
296        if (data instanceof InCallServiceImpl.CallEvent<?>) {
297            return buildCallEvent((InCallServiceImpl.CallEvent<?>) data);
298        }
299        if (data instanceof VideoProfile) {
300            return buildVideoProfile((VideoProfile) data);
301        }
302        if (data instanceof CameraCapabilities) {
303            return buildCameraCapabilities((CameraCapabilities) data);
304        }
305        if (data instanceof VoLteServiceState) {
306            return buildVoLteServiceStateEvent((VoLteServiceState) data);
307        }
308        if (data instanceof ModemActivityInfo) {
309            return buildModemActivityInfo((ModemActivityInfo) data);
310        }
311        if (data instanceof SignalStrength) {
312            return buildSignalStrength((SignalStrength) data);
313        }
314
315
316        return data.toString();
317        // throw new JSONException("Failed to build JSON result. " +
318        // data.getClass().getName());
319    }
320
321    private static JSONObject buildJsonAudioState(CallAudioState data)
322            throws JSONException {
323        JSONObject state = new JSONObject();
324        state.put("isMuted", data.isMuted());
325        state.put("AudioRoute", InCallServiceImpl.getAudioRouteString(data.getRoute()));
326        return state;
327    }
328
329    private static Object buildDisplayMetrics(DisplayMetrics data)
330            throws JSONException {
331        JSONObject dm = new JSONObject();
332        dm.put("widthPixels", data.widthPixels);
333        dm.put("heightPixels", data.heightPixels);
334        dm.put("noncompatHeightPixels", data.noncompatHeightPixels);
335        dm.put("noncompatWidthPixels", data.noncompatWidthPixels);
336        return dm;
337    }
338
339    private static Object buildInetAddress(InetAddress data) {
340        JSONArray address = new JSONArray();
341        address.put(data.getHostName());
342        address.put(data.getHostAddress());
343        return address;
344    }
345
346    private static Object buildInetSocketAddress(InetSocketAddress data) {
347        JSONArray address = new JSONArray();
348        address.put(data.getHostName());
349        address.put(data.getPort());
350        return address;
351    }
352
353    private static JSONObject buildJsonAddress(Address address)
354            throws JSONException {
355        JSONObject result = new JSONObject();
356        result.put("admin_area", address.getAdminArea());
357        result.put("country_code", address.getCountryCode());
358        result.put("country_name", address.getCountryName());
359        result.put("feature_name", address.getFeatureName());
360        result.put("phone", address.getPhone());
361        result.put("locality", address.getLocality());
362        result.put("postal_code", address.getPostalCode());
363        result.put("sub_admin_area", address.getSubAdminArea());
364        result.put("thoroughfare", address.getThoroughfare());
365        result.put("url", address.getUrl());
366        return result;
367    }
368
369    private static JSONArray buildJSONArray(Object[] data) throws JSONException {
370        JSONArray result = new JSONArray();
371        for (Object o : data) {
372            result.put(build(o));
373        }
374        return result;
375    }
376
377    private static JSONObject buildJsonBleAdvertiseSettings(
378            AdvertiseSettings advertiseSettings) throws JSONException {
379        JSONObject result = new JSONObject();
380        result.put("mode", advertiseSettings.getMode());
381        result.put("txPowerLevel", advertiseSettings.getTxPowerLevel());
382        result.put("isConnectable", advertiseSettings.isConnectable());
383        return result;
384    }
385
386    private static JSONObject buildJsonBleScanResult(
387            android.bluetooth.le.ScanResult scanResult) throws JSONException {
388        JSONObject result = new JSONObject();
389        result.put("rssi", scanResult.getRssi());
390        result.put("timestampNanos", scanResult.getTimestampNanos());
391        result.put("deviceName", scanResult.getScanRecord().getDeviceName());
392        result.put("txPowerLevel", scanResult.getScanRecord().getTxPowerLevel());
393        result.put("advertiseFlags", scanResult.getScanRecord()
394                .getAdvertiseFlags());
395        ArrayList<String> manufacturerDataList = new ArrayList<String>();
396        ArrayList<Integer> idList = new ArrayList<Integer>();
397        if (scanResult.getScanRecord().getManufacturerSpecificData() != null) {
398            SparseArray<byte[]> manufacturerSpecificData = scanResult
399                    .getScanRecord().getManufacturerSpecificData();
400            for (int i = 0; i < manufacturerSpecificData.size(); i++) {
401                manufacturerDataList.add(ConvertUtils
402                        .convertByteArrayToString(manufacturerSpecificData
403                                .valueAt(i)));
404                idList.add(manufacturerSpecificData.keyAt(i));
405            }
406        }
407        result.put("manufacturerSpecificDataList", manufacturerDataList);
408        result.put("manufacturereIdList", idList);
409        ArrayList<String> serviceUuidList = new ArrayList<String>();
410        ArrayList<String> serviceDataList = new ArrayList<String>();
411        if (scanResult.getScanRecord().getServiceData() != null) {
412            Map<ParcelUuid, byte[]> serviceDataMap = scanResult.getScanRecord()
413                    .getServiceData();
414            for (ParcelUuid serviceUuid : serviceDataMap.keySet()) {
415                serviceUuidList.add(serviceUuid.toString());
416                serviceDataList.add(ConvertUtils
417                        .convertByteArrayToString(serviceDataMap
418                                .get(serviceUuid)));
419            }
420        }
421        result.put("serviceUuidList", serviceUuidList);
422        result.put("serviceDataList", serviceDataList);
423        List<ParcelUuid> serviceUuids = scanResult.getScanRecord()
424                .getServiceUuids();
425        String serviceUuidsString = "";
426        if (serviceUuids != null && serviceUuids.size() > 0) {
427            for (ParcelUuid uuid : serviceUuids) {
428                serviceUuidsString = serviceUuidsString + "," + uuid;
429            }
430        }
431        result.put("serviceUuids", serviceUuidsString);
432        result.put("scanRecord",
433                build(ConvertUtils.convertByteArrayToString(scanResult
434                        .getScanRecord().getBytes())));
435        result.put("deviceInfo", build(scanResult.getDevice()));
436        return result;
437    }
438
439    private static JSONObject buildJsonBluetoothDevice(BluetoothDevice data)
440            throws JSONException {
441        JSONObject deviceInfo = new JSONObject();
442        deviceInfo.put("address", data.getAddress());
443        deviceInfo.put("state", data.getBondState());
444        deviceInfo.put("name", data.getName());
445        deviceInfo.put("type", data.getType());
446        return deviceInfo;
447    }
448
449    private static Object buildJsonBluetoothGattCharacteristic(
450            BluetoothGattCharacteristic data) throws JSONException {
451        JSONObject result = new JSONObject();
452        result.put("instanceId", data.getInstanceId());
453        result.put("permissions", data.getPermissions());
454        result.put("properties", data.getProperties());
455        result.put("writeType", data.getWriteType());
456        result.put("descriptorsList", build(data.getDescriptors()));
457        result.put("uuid", data.getUuid().toString());
458        result.put("value", build(data.getValue()));
459
460        return result;
461    }
462
463    private static Object buildJsonBluetoothGattDescriptor(
464            BluetoothGattDescriptor data) throws JSONException {
465        JSONObject result = new JSONObject();
466        result.put("instanceId", data.getInstanceId());
467        result.put("permissions", data.getPermissions());
468        result.put("characteristic", data.getCharacteristic());
469        result.put("uuid", data.getUuid().toString());
470        result.put("value", build(data.getValue()));
471        return result;
472    }
473
474    private static Object buildJsonBluetoothGattService(
475            BluetoothGattService data) throws JSONException {
476        JSONObject result = new JSONObject();
477        result.put("instanceId", data.getInstanceId());
478        result.put("type", data.getType());
479        result.put("gattCharacteristicList", build(data.getCharacteristics()));
480        result.put("includedServices", build(data.getIncludedServices()));
481        result.put("uuid", data.getUuid().toString());
482        return result;
483    }
484
485    private static JSONObject buildJsonBundle(Bundle bundle)
486            throws JSONException {
487        JSONObject result = new JSONObject();
488        for (String key : bundle.keySet()) {
489            result.put(key, build(bundle.get(key)));
490        }
491        return result;
492    }
493
494    private static JSONObject buildJsonCellLocation(CellLocation cellLocation)
495            throws JSONException {
496        JSONObject result = new JSONObject();
497        if (cellLocation instanceof GsmCellLocation) {
498            GsmCellLocation location = (GsmCellLocation) cellLocation;
499            result.put("lac", location.getLac());
500            result.put("cid", location.getCid());
501        }
502        // TODO(damonkohler): Add support for CdmaCellLocation. Not supported
503        // until API level 5.
504        return result;
505    }
506
507    private static JSONObject buildDhcpInfo(DhcpInfo data) throws JSONException {
508        JSONObject result = new JSONObject();
509        result.put("ipAddress", data.ipAddress);
510        result.put("dns1", data.dns1);
511        result.put("dns2", data.dns2);
512        result.put("gateway", data.gateway);
513        result.put("serverAddress", data.serverAddress);
514        result.put("leaseDuration", data.leaseDuration);
515        return result;
516    }
517
518    private static JSONObject buildJsonEvent(Event event) throws JSONException {
519        JSONObject result = new JSONObject();
520        result.put("name", event.getName());
521        result.put("data", build(event.getData()));
522        result.put("time", event.getCreationTime());
523        return result;
524    }
525
526    private static JSONObject buildJsonIntent(Intent data) throws JSONException {
527        JSONObject result = new JSONObject();
528        result.put("data", data.getDataString());
529        result.put("type", data.getType());
530        result.put("extras", build(data.getExtras()));
531        result.put("categories", build(data.getCategories()));
532        result.put("action", data.getAction());
533        ComponentName component = data.getComponent();
534        if (component != null) {
535            result.put("packagename", component.getPackageName());
536            result.put("classname", component.getClassName());
537        }
538        result.put("flags", data.getFlags());
539        return result;
540    }
541
542    private static <T> JSONArray buildJsonList(final List<T> list)
543            throws JSONException {
544        JSONArray result = new JSONArray();
545        for (T item : list) {
546            result.put(build(item));
547        }
548        return result;
549    }
550
551    private static JSONObject buildJsonLocation(Location location)
552            throws JSONException {
553        JSONObject result = new JSONObject();
554        result.put("altitude", location.getAltitude());
555        result.put("latitude", location.getLatitude());
556        result.put("longitude", location.getLongitude());
557        result.put("time", location.getTime());
558        result.put("accuracy", location.getAccuracy());
559        result.put("speed", location.getSpeed());
560        result.put("provider", location.getProvider());
561        result.put("bearing", location.getBearing());
562        return result;
563    }
564
565    private static JSONObject buildJsonMap(Map<String, ?> map)
566            throws JSONException {
567        JSONObject result = new JSONObject();
568        for (Entry<String, ?> entry : map.entrySet()) {
569            String key = entry.getKey();
570            if (key == null) {
571                key = "";
572            }
573            result.put(key, build(entry.getValue()));
574        }
575        return result;
576    }
577
578    private static JSONObject buildJsonScanResult(ScanResult scanResult)
579            throws JSONException {
580        JSONObject result = new JSONObject();
581        result.put("BSSID", scanResult.BSSID);
582        result.put("SSID", scanResult.SSID);
583        result.put("frequency", scanResult.frequency);
584        result.put("level", scanResult.level);
585        result.put("capabilities", scanResult.capabilities);
586        result.put("timestamp", scanResult.timestamp);
587        result.put("blackListTimestamp", scanResult.blackListTimestamp);
588        result.put("centerFreq0", scanResult.centerFreq0);
589        result.put("centerFreq1", scanResult.centerFreq1);
590        result.put("channelWidth", scanResult.channelWidth);
591        result.put("distanceCm", scanResult.distanceCm);
592        result.put("distanceSdCm", scanResult.distanceSdCm);
593        result.put("is80211McRTTResponder", scanResult.is80211mcResponder());
594        result.put("isAutoJoinCandidate", scanResult.isAutoJoinCandidate);
595        result.put("numConnection", scanResult.numConnection);
596        result.put("passpointNetwork", scanResult.isPasspointNetwork());
597        result.put("numIpConfigFailures", scanResult.numIpConfigFailures);
598        result.put("numUsage", scanResult.numUsage);
599        result.put("seen", scanResult.seen);
600        result.put("untrusted", scanResult.untrusted);
601        result.put("operatorFriendlyName", scanResult.operatorFriendlyName);
602        result.put("venueName", scanResult.venueName);
603        if (scanResult.informationElements != null) {
604            JSONArray infoEles = new JSONArray();
605            for (ScanResult.InformationElement ie : scanResult.informationElements) {
606                JSONObject infoEle = new JSONObject();
607                infoEle.put("id", ie.id);
608                infoEle.put("bytes", Base64Codec.encodeBase64(ie.bytes).toString());
609                infoEles.put(infoEle);
610            }
611            result.put("InfomationElements", infoEles);
612        } else {
613            result.put("InfomationElements", null);
614        }
615        return result;
616    }
617
618    private static JSONObject buildJsonScanData(ScanData scanData)
619            throws JSONException {
620        JSONObject result = new JSONObject();
621        result.put("Id", scanData.getId());
622        result.put("Flags", scanData.getFlags());
623        JSONArray scanResults = new JSONArray();
624        for (ScanResult sr : scanData.getResults()) {
625            scanResults.put(buildJsonScanResult(sr));
626        }
627        result.put("ScanResults", scanResults);
628        return result;
629    }
630
631    private static JSONObject buildJsonWifiInfo(WifiInfo data)
632            throws JSONException {
633        JSONObject result = new JSONObject();
634        result.put("hidden_ssid", data.getHiddenSSID());
635        result.put("ip_address", data.getIpAddress());
636        result.put("link_speed", data.getLinkSpeed());
637        result.put("network_id", data.getNetworkId());
638        result.put("rssi", data.getRssi());
639        result.put("BSSID", data.getBSSID());
640        result.put("mac_address", data.getMacAddress());
641        // Trim the double quotes if exist
642        String ssid = data.getSSID();
643        if (ssid.charAt(0) == '"'
644                && ssid.charAt(ssid.length() - 1) == '"') {
645            result.put("SSID", ssid.substring(1, ssid.length() - 1));
646        } else {
647            result.put("SSID", ssid);
648        }
649        String supplicantState = "";
650        switch (data.getSupplicantState()) {
651            case ASSOCIATED:
652                supplicantState = "associated";
653                break;
654            case ASSOCIATING:
655                supplicantState = "associating";
656                break;
657            case COMPLETED:
658                supplicantState = "completed";
659                break;
660            case DISCONNECTED:
661                supplicantState = "disconnected";
662                break;
663            case DORMANT:
664                supplicantState = "dormant";
665                break;
666            case FOUR_WAY_HANDSHAKE:
667                supplicantState = "four_way_handshake";
668                break;
669            case GROUP_HANDSHAKE:
670                supplicantState = "group_handshake";
671                break;
672            case INACTIVE:
673                supplicantState = "inactive";
674                break;
675            case INVALID:
676                supplicantState = "invalid";
677                break;
678            case SCANNING:
679                supplicantState = "scanning";
680                break;
681            case UNINITIALIZED:
682                supplicantState = "uninitialized";
683                break;
684            default:
685                supplicantState = null;
686        }
687        result.put("supplicant_state", build(supplicantState));
688        result.put("is_5ghz", data.is5GHz());
689        result.put("is_24ghz", data.is24GHz());
690        return result;
691    }
692
693    private static JSONObject buildNeighboringCellInfo(NeighboringCellInfo data)
694            throws JSONException {
695        JSONObject result = new JSONObject();
696        result.put("cid", data.getCid());
697        result.put("rssi", data.getRssi());
698        result.put("lac", data.getLac());
699        result.put("psc", data.getPsc());
700        String networkType =
701                TelephonyUtils.getNetworkTypeString(data.getNetworkType());
702        result.put("network_type", build(networkType));
703        return result;
704    }
705
706    private static JSONObject buildCellInfoLte(CellInfoLte data)
707            throws JSONException {
708        JSONObject result = new JSONObject();
709        result.put("rat", "lte");
710        result.put("registered", data.isRegistered());
711        CellIdentityLte cellidentity =
712                ((CellInfoLte) data).getCellIdentity();
713        CellSignalStrengthLte signalstrength =
714                ((CellInfoLte) data).getCellSignalStrength();
715        result.put("mcc", cellidentity.getMcc());
716        result.put("mnc", cellidentity.getMnc());
717        result.put("cid", cellidentity.getCi());
718        result.put("pcid", cellidentity.getPci());
719        result.put("tac", cellidentity.getTac());
720        result.put("rsrp", signalstrength.getDbm());
721        result.put("asulevel", signalstrength.getAsuLevel());
722        result.put("timing_advance", signalstrength.getTimingAdvance());
723        return result;
724    }
725
726    private static JSONObject buildCellInfoGsm(CellInfoGsm data)
727            throws JSONException {
728        JSONObject result = new JSONObject();
729        result.put("rat", "gsm");
730        result.put("registered", data.isRegistered());
731        CellIdentityGsm cellidentity =
732                ((CellInfoGsm) data).getCellIdentity();
733        CellSignalStrengthGsm signalstrength =
734                ((CellInfoGsm) data).getCellSignalStrength();
735        result.put("mcc", cellidentity.getMcc());
736        result.put("mnc", cellidentity.getMnc());
737        result.put("cid", cellidentity.getCid());
738        result.put("lac", cellidentity.getLac());
739        result.put("signal_strength", signalstrength.getDbm());
740        result.put("asulevel", signalstrength.getAsuLevel());
741        return result;
742    }
743
744    private static JSONObject buildCellInfoWcdma(CellInfoWcdma data)
745            throws JSONException {
746        JSONObject result = new JSONObject();
747        result.put("rat", "wcdma");
748        result.put("registered", data.isRegistered());
749        CellIdentityWcdma cellidentity =
750                ((CellInfoWcdma) data).getCellIdentity();
751        CellSignalStrengthWcdma signalstrength =
752                ((CellInfoWcdma) data).getCellSignalStrength();
753        result.put("mcc", cellidentity.getMcc());
754        result.put("mnc", cellidentity.getMnc());
755        result.put("cid", cellidentity.getCid());
756        result.put("lac", cellidentity.getLac());
757        result.put("psc", cellidentity.getPsc());
758        result.put("signal_strength", signalstrength.getDbm());
759        result.put("asulevel", signalstrength.getAsuLevel());
760        return result;
761    }
762
763    private static JSONObject buildCellInfoCdma(CellInfoCdma data)
764            throws JSONException {
765        JSONObject result = new JSONObject();
766        result.put("rat", "cdma");
767        result.put("registered", data.isRegistered());
768        CellIdentityCdma cellidentity =
769                ((CellInfoCdma) data).getCellIdentity();
770        CellSignalStrengthCdma signalstrength =
771                ((CellInfoCdma) data).getCellSignalStrength();
772        result.put("network_id", cellidentity.getNetworkId());
773        result.put("system_id", cellidentity.getSystemId());
774        result.put("basestation_id", cellidentity.getBasestationId());
775        result.put("longitude", cellidentity.getLongitude());
776        result.put("latitude", cellidentity.getLatitude());
777        result.put("cdma_dbm", signalstrength.getCdmaDbm());
778        result.put("cdma_ecio", signalstrength.getCdmaEcio());
779        result.put("evdo_dbm", signalstrength.getEvdoDbm());
780        result.put("evdo_ecio", signalstrength.getEvdoEcio());
781        result.put("evdo_snr", signalstrength.getEvdoSnr());
782        return result;
783    }
784
785    private static Object buildHttpURLConnection(HttpURLConnection data)
786            throws JSONException {
787        JSONObject con = new JSONObject();
788        try {
789            con.put("ResponseCode", data.getResponseCode());
790            con.put("ResponseMessage", data.getResponseMessage());
791        } catch (IOException e) {
792            e.printStackTrace();
793            return con;
794        }
795        con.put("ContentLength", data.getContentLength());
796        con.put("ContentEncoding", data.getContentEncoding());
797        con.put("ContentType", data.getContentType());
798        con.put("Date", data.getDate());
799        con.put("ReadTimeout", data.getReadTimeout());
800        con.put("HeaderFields", buildJsonMap(data.getHeaderFields()));
801        con.put("URL", buildURL(data.getURL()));
802        return con;
803    }
804
805    private static Object buildNetwork(Network data) throws JSONException {
806        JSONObject nw = new JSONObject();
807        nw.put("netId", data.netId);
808        return nw;
809    }
810
811    private static Object buildNetworkInfo(NetworkInfo data)
812            throws JSONException {
813        JSONObject info = new JSONObject();
814        info.put("isAvailable", data.isAvailable());
815        info.put("isConnected", data.isConnected());
816        info.put("isFailover", data.isFailover());
817        info.put("isRoaming", data.isRoaming());
818        info.put("ExtraInfo", data.getExtraInfo());
819        info.put("FailedReason", data.getReason());
820        info.put("TypeName", data.getTypeName());
821        info.put("SubtypeName", data.getSubtypeName());
822        info.put("State", data.getState().name().toString());
823        return info;
824    }
825
826    private static Object buildURL(URL data) throws JSONException {
827        JSONObject url = new JSONObject();
828        url.put("Authority", data.getAuthority());
829        url.put("Host", data.getHost());
830        url.put("Path", data.getPath());
831        url.put("Port", data.getPort());
832        url.put("Protocol", data.getProtocol());
833        return url;
834    }
835
836    private static JSONObject buildPhoneAccount(PhoneAccount data)
837            throws JSONException {
838        JSONObject acct = new JSONObject();
839        acct.put("Address", data.getAddress().toSafeString());
840        acct.put("SubscriptionAddress", data.getSubscriptionAddress()
841                .toSafeString());
842        acct.put("Label", ((data.getLabel() != null) ? data.getLabel().toString() : ""));
843        acct.put("ShortDescription", ((data.getShortDescription() != null) ? data
844                .getShortDescription().toString() : ""));
845        return acct;
846    }
847
848    private static Object buildPhoneAccountHandle(PhoneAccountHandle data)
849            throws JSONException {
850        JSONObject msg = new JSONObject();
851        msg.put("id", data.getId());
852        msg.put("ComponentName", data.getComponentName().flattenToString());
853        return msg;
854    }
855
856    private static Object buildSubscriptionInfoRecord(SubscriptionInfo data)
857            throws JSONException {
858        JSONObject msg = new JSONObject();
859        msg.put("subscriptionId", data.getSubscriptionId());
860        msg.put("iccId", data.getIccId());
861        msg.put("simSlotIndex", data.getSimSlotIndex());
862        msg.put("displayName", data.getDisplayName());
863        msg.put("nameSource", data.getNameSource());
864        msg.put("iconTint", data.getIconTint());
865        msg.put("number", data.getNumber());
866        msg.put("dataRoaming", data.getDataRoaming());
867        msg.put("mcc", data.getMcc());
868        msg.put("mnc", data.getMnc());
869        return msg;
870    }
871
872    private static Object buildPoint(Point data) throws JSONException {
873        JSONObject point = new JSONObject();
874        point.put("x", data.x);
875        point.put("y", data.y);
876        return point;
877    }
878
879    private static Object buildRttCapabilities(RttCapabilities data)
880            throws JSONException {
881        JSONObject cap = new JSONObject();
882        cap.put("bwSupported", data.bwSupported);
883        cap.put("lciSupported", data.lciSupported);
884        cap.put("lcrSupported", data.lcrSupported);
885        cap.put("oneSidedRttSupported", data.oneSidedRttSupported);
886        cap.put("preambleSupported", data.preambleSupported);
887        cap.put("twoSided11McRttSupported", data.twoSided11McRttSupported);
888        return cap;
889    }
890
891    private static Object buildSmsMessage(SmsMessage data) throws JSONException {
892        JSONObject msg = new JSONObject();
893        msg.put("originatingAddress", data.getOriginatingAddress());
894        msg.put("messageBody", data.getMessageBody());
895        return msg;
896    }
897
898    private static JSONObject buildWifiActivityEnergyInfo(
899            WifiActivityEnergyInfo data) throws JSONException {
900        JSONObject result = new JSONObject();
901        result.put("ControllerEnergyUsed", data.getControllerEnergyUsed());
902        result.put("ControllerIdleTimeMillis",
903                data.getControllerIdleTimeMillis());
904        result.put("ControllerRxTimeMillis", data.getControllerRxTimeMillis());
905        result.put("ControllerTxTimeMillis", data.getControllerTxTimeMillis());
906        result.put("StackState", data.getStackState());
907        result.put("TimeStamp", data.getTimeStamp());
908        return result;
909    }
910
911    private static Object buildWifiChannel(WifiChannel data) throws JSONException {
912        JSONObject channel = new JSONObject();
913        channel.put("channelNum", data.channelNum);
914        channel.put("freqMHz", data.freqMHz);
915        channel.put("isDFS", data.isDFS);
916        channel.put("isValid", data.isValid());
917        return channel;
918    }
919
920    private static Object buildWifiConfiguration(WifiConfiguration data)
921            throws JSONException {
922        JSONObject config = new JSONObject();
923        config.put("networkId", data.networkId);
924        // Trim the double quotes if exist
925        if (data.SSID.charAt(0) == '"'
926                && data.SSID.charAt(data.SSID.length() - 1) == '"') {
927            config.put("SSID", data.SSID.substring(1, data.SSID.length() - 1));
928        } else {
929            config.put("SSID", data.SSID);
930        }
931        config.put("BSSID", data.BSSID);
932        config.put("priority", data.priority);
933        config.put("hiddenSSID", data.hiddenSSID);
934        config.put("FQDN", data.FQDN);
935        config.put("providerFriendlyName", data.providerFriendlyName);
936        config.put("isPasspoint", data.isPasspoint());
937        config.put("hiddenSSID", data.hiddenSSID);
938        if (data.status == WifiConfiguration.Status.CURRENT) {
939            config.put("status", "CURRENT");
940        } else if (data.status == WifiConfiguration.Status.DISABLED) {
941            config.put("status", "DISABLED");
942        } else if (data.status == WifiConfiguration.Status.ENABLED) {
943            config.put("status", "ENABLED");
944        } else {
945            config.put("status", "UNKNOWN");
946        }
947        // config.put("enterpriseConfig", buildWifiEnterpriseConfig(data.enterpriseConfig));
948        return config;
949    }
950
951    private static Object buildWifiEnterpriseConfig(WifiEnterpriseConfig data)
952            throws JSONException, CertificateEncodingException {
953        JSONObject config = new JSONObject();
954        config.put(WifiEnterpriseConfig.PLMN_KEY, data.getPlmn());
955        config.put(WifiEnterpriseConfig.REALM_KEY, data.getRealm());
956        config.put(WifiEnterpriseConfig.EAP_KEY, data.getEapMethod());
957        config.put(WifiEnterpriseConfig.PHASE2_KEY, data.getPhase2Method());
958        config.put(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, data.getAltSubjectMatch());
959        X509Certificate caCert = data.getCaCertificate();
960        String caCertString = Base64.encodeToString(caCert.getEncoded(), Base64.DEFAULT);
961        config.put(WifiEnterpriseConfig.CA_CERT_KEY, caCertString);
962        X509Certificate clientCert = data.getClientCertificate();
963        String clientCertString = Base64.encodeToString(clientCert.getEncoded(), Base64.DEFAULT);
964        config.put(WifiEnterpriseConfig.CLIENT_CERT_KEY, clientCertString);
965        PrivateKey pk = data.getClientPrivateKey();
966        String privateKeyString = Base64.encodeToString(pk.getEncoded(), Base64.DEFAULT);
967        config.put(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, privateKeyString);
968        config.put(WifiEnterpriseConfig.PASSWORD_KEY, data.getPassword());
969        return config;
970    }
971
972    private static JSONObject buildWifiP2pDevice(WifiP2pDevice data)
973            throws JSONException {
974        JSONObject deviceInfo = new JSONObject();
975        deviceInfo.put("Name", data.deviceName);
976        deviceInfo.put("Address", data.deviceAddress);
977        return deviceInfo;
978    }
979
980    private static JSONObject buildWifiP2pGroup(WifiP2pGroup data)
981            throws JSONException {
982        JSONObject group = new JSONObject();
983        Log.d("build p2p group.");
984        group.put("ClientList", build(data.getClientList()));
985        group.put("Interface", data.getInterface());
986        group.put("Networkname", data.getNetworkName());
987        group.put("Owner", data.getOwner());
988        group.put("Passphrase", data.getPassphrase());
989        group.put("NetworkId", data.getNetworkId());
990        return group;
991    }
992
993    private static JSONObject buildWifiP2pInfo(WifiP2pInfo data)
994            throws JSONException {
995        JSONObject info = new JSONObject();
996        Log.d("build p2p info.");
997        info.put("groupFormed", data.groupFormed);
998        info.put("isGroupOwner", data.isGroupOwner);
999        info.put("groupOwnerAddress", data.groupOwnerAddress);
1000        return info;
1001    }
1002
1003    private static <T> JSONObject buildCallEvent(InCallServiceImpl.CallEvent<T> callEvent)
1004            throws JSONException {
1005        JSONObject jsonEvent = new JSONObject();
1006        jsonEvent.put("CallId", callEvent.getCallId());
1007        jsonEvent.put("Event", build(callEvent.getEvent()));
1008        return jsonEvent;
1009    }
1010
1011    private static JSONObject buildUri(Uri uri) throws JSONException {
1012        return new JSONObject().put("Uri", build((uri != null) ? uri.toString() : ""));
1013    }
1014
1015    private static JSONObject buildCallDetails(Call.Details details) throws JSONException {
1016
1017        JSONObject callDetails = new JSONObject();
1018
1019        callDetails.put("Handle", buildUri(details.getHandle()));
1020        callDetails.put("HandlePresentation",
1021                build(InCallServiceImpl.getCallPresentationInfoString(
1022                        details.getHandlePresentation())));
1023        callDetails.put("CallerDisplayName", build(details.getCallerDisplayName()));
1024
1025        // TODO AccountHandle
1026        // callDetails.put("AccountHandle", build(""));
1027
1028        callDetails.put("Capabilities",
1029                build(InCallServiceImpl.getCallCapabilitiesString(details.getCallCapabilities())));
1030
1031        callDetails.put("Properties",
1032                build(InCallServiceImpl.getCallPropertiesString(details.getCallProperties())));
1033
1034        // TODO Parse fields in Disconnect Cause
1035        callDetails.put("DisconnectCause", build((details.getDisconnectCause() != null) ? details
1036                .getDisconnectCause().toString() : ""));
1037        callDetails.put("ConnectTimeMillis", build(details.getConnectTimeMillis()));
1038
1039        // TODO: GatewayInfo
1040        // callDetails.put("GatewayInfo", build(""));
1041
1042        callDetails.put("VideoState",
1043                build(InCallServiceImpl.getVideoCallStateString(details.getVideoState())));
1044
1045        // TODO: StatusHints
1046        // callDetails.put("StatusHints", build(""));
1047
1048        callDetails.put("Extras", build(details.getExtras()));
1049
1050        return callDetails;
1051    }
1052
1053    private static JSONObject buildCall(Call call) throws JSONException {
1054
1055        JSONObject callInfo = new JSONObject();
1056
1057        callInfo.put("Parent", build(InCallServiceImpl.getCallId(call)));
1058
1059        // TODO:Make a function out of this for consistency
1060        ArrayList<String> children = new ArrayList<String>();
1061        for (Call child : call.getChildren()) {
1062            children.add(InCallServiceImpl.getCallId(child));
1063        }
1064        callInfo.put("Children", build(children));
1065
1066        // TODO:Make a function out of this for consistency
1067        ArrayList<String> conferenceables = new ArrayList<String>();
1068        for (Call conferenceable : call.getChildren()) {
1069            children.add(InCallServiceImpl.getCallId(conferenceable));
1070        }
1071        callInfo.put("ConferenceableCalls", build(conferenceables));
1072
1073        callInfo.put("State", build(InCallServiceImpl.getCallStateString(call.getState())));
1074        callInfo.put("CannedTextResponses", build(call.getCannedTextResponses()));
1075        callInfo.put("VideoCall", InCallServiceImpl.getVideoCallId(call.getVideoCall()));
1076        callInfo.put("Details", build(call.getDetails()));
1077
1078        return callInfo;
1079    }
1080
1081    private static JSONObject buildVideoProfile(VideoProfile videoProfile) throws JSONException {
1082        JSONObject profile = new JSONObject();
1083
1084        profile.put("VideoState",
1085                InCallServiceImpl.getVideoCallStateString(videoProfile.getVideoState()));
1086        profile.put("VideoQuality",
1087                InCallServiceImpl.getVideoCallQualityString(videoProfile.getQuality()));
1088
1089        return profile;
1090    }
1091
1092    private static JSONObject buildCameraCapabilities(CameraCapabilities cameraCapabilities)
1093            throws JSONException {
1094        JSONObject capabilities = new JSONObject();
1095
1096        capabilities.put("Height", build(cameraCapabilities.getHeight()));
1097        capabilities.put("Width", build(cameraCapabilities.getWidth()));
1098        capabilities.put("ZoomSupported", build(cameraCapabilities.isZoomSupported()));
1099        capabilities.put("MaxZoom", build(cameraCapabilities.getMaxZoom()));
1100
1101        return capabilities;
1102    }
1103
1104    private static JSONObject buildVoLteServiceStateEvent(
1105        VoLteServiceState volteInfo)
1106            throws JSONException {
1107        JSONObject info = new JSONObject();
1108        info.put(TelephonyConstants.VoLteServiceStateContainer.SRVCC_STATE,
1109            TelephonyUtils.getSrvccStateString(volteInfo.getSrvccState()));
1110        return info;
1111    }
1112
1113    private static JSONObject buildModemActivityInfo(ModemActivityInfo modemInfo)
1114            throws JSONException {
1115        JSONObject info = new JSONObject();
1116
1117        info.put("Timestamp", modemInfo.getTimestamp());
1118        info.put("SleepTimeMs", modemInfo.getSleepTimeMillis());
1119        info.put("IdleTimeMs", modemInfo.getIdleTimeMillis());
1120        //convert from int[] to List<Integer> for proper JSON translation
1121        int[] txTimes = modemInfo.getTxTimeMillis();
1122        List<Integer> tmp = new ArrayList<Integer>(txTimes.length);
1123        for(int val : txTimes) {
1124            tmp.add(val);
1125        }
1126        info.put("TxTimeMs", build(tmp));
1127        info.put("RxTimeMs", modemInfo.getRxTimeMillis());
1128        info.put("EnergyUsedMw", modemInfo.getEnergyUsed());
1129        return info;
1130    }
1131    private static JSONObject buildSignalStrength(SignalStrength signalStrength)
1132            throws JSONException {
1133        JSONObject info = new JSONObject();
1134        info.put(TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_GSM,
1135            signalStrength.getGsmSignalStrength());
1136        info.put(
1137            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_GSM_DBM,
1138            signalStrength.getGsmDbm());
1139        info.put(
1140            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_GSM_LEVEL,
1141            signalStrength.getGsmLevel());
1142        info.put(
1143            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_GSM_ASU_LEVEL,
1144            signalStrength.getGsmAsuLevel());
1145        info.put(
1146            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_GSM_BIT_ERROR_RATE,
1147            signalStrength.getGsmBitErrorRate());
1148        info.put(
1149            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_CDMA_DBM,
1150            signalStrength.getCdmaDbm());
1151        info.put(
1152            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_CDMA_LEVEL,
1153            signalStrength.getCdmaLevel());
1154        info.put(
1155            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_CDMA_ASU_LEVEL,
1156            signalStrength.getCdmaAsuLevel());
1157        info.put(
1158            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_CDMA_ECIO,
1159            signalStrength.getCdmaEcio());
1160        info.put(
1161            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_EVDO_DBM,
1162            signalStrength.getEvdoDbm());
1163        info.put(
1164            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_EVDO_ECIO,
1165            signalStrength.getEvdoEcio());
1166        info.put(TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_LTE,
1167            signalStrength.getLteSignalStrength());
1168        info.put(
1169            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_LTE_DBM,
1170            signalStrength.getLteDbm());
1171        info.put(
1172            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_LTE_LEVEL,
1173            signalStrength.getLteLevel());
1174        info.put(
1175            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_LTE_ASU_LEVEL,
1176            signalStrength.getLteAsuLevel());
1177        info.put(
1178            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_LEVEL,
1179            signalStrength.getLevel());
1180        info.put(
1181            TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_ASU_LEVEL,
1182            signalStrength.getAsuLevel());
1183        info.put(TelephonyConstants.SignalStrengthContainer.SIGNAL_STRENGTH_DBM,
1184            signalStrength.getDbm());
1185        return info;
1186    }
1187
1188    private JsonBuilder() {
1189        // This is a utility class.
1190    }
1191}
1192