1*3ba32fe9SKudo Chien /*
2*3ba32fe9SKudo Chien  * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
3*3ba32fe9SKudo Chien  *
4*3ba32fe9SKudo Chien  * You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
5*3ba32fe9SKudo Chien  * copy, modify, and distribute this software in source code or binary form for use
6*3ba32fe9SKudo Chien  * in connection with the web services and APIs provided by Facebook.
7*3ba32fe9SKudo Chien  *
8*3ba32fe9SKudo Chien  * As with any software that integrates with the Facebook platform, your use of
9*3ba32fe9SKudo Chien  * this software is subject to the Facebook Developer Principles and Policies
10*3ba32fe9SKudo Chien  * [http://developers.facebook.com/policy/]. This copyright notice shall be
11*3ba32fe9SKudo Chien  * included in all copies or substantial portions of the software.
12*3ba32fe9SKudo Chien  *
13*3ba32fe9SKudo Chien  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14*3ba32fe9SKudo Chien  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15*3ba32fe9SKudo Chien  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16*3ba32fe9SKudo Chien  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17*3ba32fe9SKudo Chien  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18*3ba32fe9SKudo Chien  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19*3ba32fe9SKudo Chien  */
20*3ba32fe9SKudo Chien 
21*3ba32fe9SKudo Chien package host.exp.exponent.utils
22*3ba32fe9SKudo Chien 
23*3ba32fe9SKudo Chien import android.os.Bundle
24*3ba32fe9SKudo Chien import org.json.JSONArray
25*3ba32fe9SKudo Chien import org.json.JSONException
26*3ba32fe9SKudo Chien import org.json.JSONObject
27*3ba32fe9SKudo Chien 
28*3ba32fe9SKudo Chien /**
29*3ba32fe9SKudo Chien  * Referenced from [com.facebook.internal.BundleJSONConverter]
30*3ba32fe9SKudo Chien  * https://github.com/facebook/facebook-android-sdk/blob/main/facebook-core/src/main/java/com/facebook/internal/BundleJSONConverter.kt
31*3ba32fe9SKudo Chien  *
32*3ba32fe9SKudo Chien  * com.facebook.internal is solely for the use of other packages within the Facebook SDK for
33*3ba32fe9SKudo Chien  * Android. Use of any of the classes in this package is unsupported, and they may be modified or
34*3ba32fe9SKudo Chien  * removed without warning at any time.
35*3ba32fe9SKudo Chien  *
36*3ba32fe9SKudo Chien  * A helper class that can round trip between JSON and Bundle objects that contains the types:
37*3ba32fe9SKudo Chien  * Boolean, Integer, Long, Double, String If other types are found, an IllegalArgumentException is
38*3ba32fe9SKudo Chien  * thrown.
39*3ba32fe9SKudo Chien  */
40*3ba32fe9SKudo Chien 
41*3ba32fe9SKudo Chien object BundleJSONConverter {
42*3ba32fe9SKudo Chien   private val SETTERS: MutableMap<Class<*>, Setter> = HashMap()
43*3ba32fe9SKudo Chien 
44*3ba32fe9SKudo Chien   @JvmStatic
45*3ba32fe9SKudo Chien   @Throws(JSONException::class)
convertToJSONnull46*3ba32fe9SKudo Chien   fun convertToJSON(bundle: Bundle): JSONObject {
47*3ba32fe9SKudo Chien     val json = JSONObject()
48*3ba32fe9SKudo Chien     for (key in bundle.keySet()) {
49*3ba32fe9SKudo Chien       val value =
50*3ba32fe9SKudo Chien         bundle[key] // Null is not supported.
51*3ba32fe9SKudo Chien           ?: continue
52*3ba32fe9SKudo Chien 
53*3ba32fe9SKudo Chien       // Special case List<String> as getClass would not work, since List is an interface
54*3ba32fe9SKudo Chien       if (value is List<*>) {
55*3ba32fe9SKudo Chien         val jsonArray = JSONArray()
56*3ba32fe9SKudo Chien         val listValue = value as List<String>
57*3ba32fe9SKudo Chien         for (stringValue in listValue) {
58*3ba32fe9SKudo Chien           jsonArray.put(stringValue)
59*3ba32fe9SKudo Chien         }
60*3ba32fe9SKudo Chien         json.put(key, jsonArray)
61*3ba32fe9SKudo Chien         continue
62*3ba32fe9SKudo Chien       }
63*3ba32fe9SKudo Chien 
64*3ba32fe9SKudo Chien       // Special case Bundle as it's one way, on the return it will be JSONObject
65*3ba32fe9SKudo Chien       if (value is Bundle) {
66*3ba32fe9SKudo Chien         json.put(key, convertToJSON(value))
67*3ba32fe9SKudo Chien         continue
68*3ba32fe9SKudo Chien       }
69*3ba32fe9SKudo Chien       val setter =
70*3ba32fe9SKudo Chien         SETTERS[value.javaClass]
71*3ba32fe9SKudo Chien           ?: throw IllegalArgumentException("Unsupported type: " + value.javaClass)
72*3ba32fe9SKudo Chien       setter.setOnJSON(json, key, value)
73*3ba32fe9SKudo Chien     }
74*3ba32fe9SKudo Chien     return json
75*3ba32fe9SKudo Chien   }
76*3ba32fe9SKudo Chien 
77*3ba32fe9SKudo Chien   @JvmStatic
78*3ba32fe9SKudo Chien   @Throws(JSONException::class)
convertToBundlenull79*3ba32fe9SKudo Chien   fun convertToBundle(jsonObject: JSONObject): Bundle {
80*3ba32fe9SKudo Chien     val bundle = Bundle()
81*3ba32fe9SKudo Chien     val jsonIterator = jsonObject.keys()
82*3ba32fe9SKudo Chien     while (jsonIterator.hasNext()) {
83*3ba32fe9SKudo Chien       val key = jsonIterator.next()
84*3ba32fe9SKudo Chien       val value = jsonObject[key]
85*3ba32fe9SKudo Chien       if (value === JSONObject.NULL) {
86*3ba32fe9SKudo Chien         // Null is not supported.
87*3ba32fe9SKudo Chien         continue
88*3ba32fe9SKudo Chien       }
89*3ba32fe9SKudo Chien 
90*3ba32fe9SKudo Chien       // Special case JSONObject as it's one way, on the return it would be Bundle.
91*3ba32fe9SKudo Chien       if (value is JSONObject) {
92*3ba32fe9SKudo Chien         bundle.putBundle(key, convertToBundle(value))
93*3ba32fe9SKudo Chien         continue
94*3ba32fe9SKudo Chien       }
95*3ba32fe9SKudo Chien       val setter =
96*3ba32fe9SKudo Chien         SETTERS[value.javaClass]
97*3ba32fe9SKudo Chien           ?: throw IllegalArgumentException("Unsupported type: " + value.javaClass)
98*3ba32fe9SKudo Chien       setter.setOnBundle(bundle, key, value)
99*3ba32fe9SKudo Chien     }
100*3ba32fe9SKudo Chien     return bundle
101*3ba32fe9SKudo Chien   }
102*3ba32fe9SKudo Chien 
103*3ba32fe9SKudo Chien   interface Setter {
setOnBundlenull104*3ba32fe9SKudo Chien     @Throws(JSONException::class) fun setOnBundle(bundle: Bundle, key: String, value: Any)
105*3ba32fe9SKudo Chien 
106*3ba32fe9SKudo Chien     @Throws(JSONException::class) fun setOnJSON(json: JSONObject, key: String, value: Any)
107*3ba32fe9SKudo Chien   }
108*3ba32fe9SKudo Chien 
109*3ba32fe9SKudo Chien   init {
110*3ba32fe9SKudo Chien     SETTERS[java.lang.Boolean::class.java] =
111*3ba32fe9SKudo Chien       object : Setter {
112*3ba32fe9SKudo Chien         @Throws(JSONException::class)
113*3ba32fe9SKudo Chien         override fun setOnBundle(bundle: Bundle, key: String, value: Any) {
114*3ba32fe9SKudo Chien           bundle.putBoolean(key, value as Boolean)
115*3ba32fe9SKudo Chien         }
116*3ba32fe9SKudo Chien 
117*3ba32fe9SKudo Chien         @Throws(JSONException::class)
118*3ba32fe9SKudo Chien         override fun setOnJSON(json: JSONObject, key: String, value: Any) {
119*3ba32fe9SKudo Chien           json.put(key, value)
120*3ba32fe9SKudo Chien         }
121*3ba32fe9SKudo Chien       }
122*3ba32fe9SKudo Chien     SETTERS[java.lang.Integer::class.java] =
123*3ba32fe9SKudo Chien       object : Setter {
124*3ba32fe9SKudo Chien         @Throws(JSONException::class)
125*3ba32fe9SKudo Chien         override fun setOnBundle(bundle: Bundle, key: String, value: Any) {
126*3ba32fe9SKudo Chien           bundle.putInt(key, value as Int)
127*3ba32fe9SKudo Chien         }
128*3ba32fe9SKudo Chien 
129*3ba32fe9SKudo Chien         @Throws(JSONException::class)
130*3ba32fe9SKudo Chien         override fun setOnJSON(json: JSONObject, key: String, value: Any) {
131*3ba32fe9SKudo Chien           json.put(key, value)
132*3ba32fe9SKudo Chien         }
133*3ba32fe9SKudo Chien       }
134*3ba32fe9SKudo Chien     SETTERS[java.lang.Long::class.java] =
135*3ba32fe9SKudo Chien       object : Setter {
136*3ba32fe9SKudo Chien         @Throws(JSONException::class)
137*3ba32fe9SKudo Chien         override fun setOnBundle(bundle: Bundle, key: String, value: Any) {
138*3ba32fe9SKudo Chien           bundle.putLong(key, value as Long)
139*3ba32fe9SKudo Chien         }
140*3ba32fe9SKudo Chien 
141*3ba32fe9SKudo Chien         @Throws(JSONException::class)
142*3ba32fe9SKudo Chien         override fun setOnJSON(json: JSONObject, key: String, value: Any) {
143*3ba32fe9SKudo Chien           json.put(key, value)
144*3ba32fe9SKudo Chien         }
145*3ba32fe9SKudo Chien       }
146*3ba32fe9SKudo Chien     SETTERS[java.lang.Double::class.java] =
147*3ba32fe9SKudo Chien       object : Setter {
148*3ba32fe9SKudo Chien         @Throws(JSONException::class)
149*3ba32fe9SKudo Chien         override fun setOnBundle(bundle: Bundle, key: String, value: Any) {
150*3ba32fe9SKudo Chien           bundle.putDouble(key, value as Double)
151*3ba32fe9SKudo Chien         }
152*3ba32fe9SKudo Chien 
153*3ba32fe9SKudo Chien         @Throws(JSONException::class)
154*3ba32fe9SKudo Chien         override fun setOnJSON(json: JSONObject, key: String, value: Any) {
155*3ba32fe9SKudo Chien           json.put(key, value)
156*3ba32fe9SKudo Chien         }
157*3ba32fe9SKudo Chien       }
158*3ba32fe9SKudo Chien     SETTERS[String::class.java] =
159*3ba32fe9SKudo Chien       object : Setter {
160*3ba32fe9SKudo Chien         @Throws(JSONException::class)
161*3ba32fe9SKudo Chien         override fun setOnBundle(bundle: Bundle, key: String, value: Any) {
162*3ba32fe9SKudo Chien           bundle.putString(key, value as String)
163*3ba32fe9SKudo Chien         }
164*3ba32fe9SKudo Chien 
165*3ba32fe9SKudo Chien         @Throws(JSONException::class)
166*3ba32fe9SKudo Chien         override fun setOnJSON(json: JSONObject, key: String, value: Any) {
167*3ba32fe9SKudo Chien           json.put(key, value)
168*3ba32fe9SKudo Chien         }
169*3ba32fe9SKudo Chien       }
170*3ba32fe9SKudo Chien     SETTERS[Array<String>::class.java] =
171*3ba32fe9SKudo Chien       object : Setter {
172*3ba32fe9SKudo Chien         @Throws(JSONException::class)
173*3ba32fe9SKudo Chien         override fun setOnBundle(bundle: Bundle, key: String, value: Any) {
174*3ba32fe9SKudo Chien           throw IllegalArgumentException("Unexpected type from JSON")
175*3ba32fe9SKudo Chien         }
176*3ba32fe9SKudo Chien 
177*3ba32fe9SKudo Chien         @Throws(JSONException::class)
178*3ba32fe9SKudo Chien         override fun setOnJSON(json: JSONObject, key: String, value: Any) {
179*3ba32fe9SKudo Chien           val jsonArray = JSONArray()
180*3ba32fe9SKudo Chien           for (stringValue in value as Array<String>) {
181*3ba32fe9SKudo Chien             jsonArray.put(stringValue)
182*3ba32fe9SKudo Chien           }
183*3ba32fe9SKudo Chien           json.put(key, jsonArray)
184*3ba32fe9SKudo Chien         }
185*3ba32fe9SKudo Chien       }
186*3ba32fe9SKudo Chien     SETTERS[JSONArray::class.java] =
187*3ba32fe9SKudo Chien       object : Setter {
188*3ba32fe9SKudo Chien         @Throws(JSONException::class)
189*3ba32fe9SKudo Chien         override fun setOnBundle(bundle: Bundle, key: String, value: Any) {
190*3ba32fe9SKudo Chien           val jsonArray = value as JSONArray
191*3ba32fe9SKudo Chien           val stringArrayList = ArrayList<String>()
192*3ba32fe9SKudo Chien           // Empty list, can't even figure out the type, assume an ArrayList<String>
193*3ba32fe9SKudo Chien           if (jsonArray.length() == 0) {
194*3ba32fe9SKudo Chien             bundle.putStringArrayList(key, stringArrayList)
195*3ba32fe9SKudo Chien             return
196*3ba32fe9SKudo Chien           }
197*3ba32fe9SKudo Chien 
198*3ba32fe9SKudo Chien           // Only strings are supported for now
199*3ba32fe9SKudo Chien           for (i in 0 until jsonArray.length()) {
200*3ba32fe9SKudo Chien             val current = jsonArray[i]
201*3ba32fe9SKudo Chien             if (current is String) {
202*3ba32fe9SKudo Chien               stringArrayList.add(current)
203*3ba32fe9SKudo Chien             } else {
204*3ba32fe9SKudo Chien               throw IllegalArgumentException("Unexpected type in an array: " + current.javaClass)
205*3ba32fe9SKudo Chien             }
206*3ba32fe9SKudo Chien           }
207*3ba32fe9SKudo Chien           bundle.putStringArrayList(key, stringArrayList)
208*3ba32fe9SKudo Chien         }
209*3ba32fe9SKudo Chien 
210*3ba32fe9SKudo Chien         @Throws(JSONException::class)
211*3ba32fe9SKudo Chien         override fun setOnJSON(json: JSONObject, key: String, value: Any) {
212*3ba32fe9SKudo Chien           throw IllegalArgumentException("JSONArray's are not supported in bundles.")
213*3ba32fe9SKudo Chien         }
214*3ba32fe9SKudo Chien       }
215*3ba32fe9SKudo Chien   }
216*3ba32fe9SKudo Chien }
217