<lambda>null1 package host.exp.exponent.experience.splashscreen
2 
3 import android.graphics.Color
4 import androidx.annotation.ColorInt
5 import expo.modules.jsonutils.getNullable
6 import expo.modules.splashscreen.SplashScreenImageResizeMode
7 import expo.modules.manifests.core.Manifest
8 import host.exp.exponent.ExponentManifest
9 import host.exp.exponent.utils.ColorParser
10 import org.json.JSONObject
11 
12 class ManagedAppSplashScreenConfiguration private constructor() {
13   var resizeMode: SplashScreenImageResizeMode = SplashScreenImageResizeMode.CONTAIN
14     private set
15 
16   @ColorInt
17   var backgroundColor = Color.parseColor("#ffffff")
18     private set
19   var imageUrl: String? = null
20     private set
21 
22   companion object {
23     @JvmStatic
24     fun parseManifest(manifest: Manifest): ManagedAppSplashScreenConfiguration {
25       val mode: SplashScreenImageResizeMode? = parseResizeMode(manifest)
26       val backgroundColor = parseBackgroundColor(manifest)
27       val imageUrl = parseImageUrl(manifest)
28       val config = ManagedAppSplashScreenConfiguration()
29       if (mode != null) {
30         config.resizeMode = mode
31       }
32       if (backgroundColor != null) {
33         config.backgroundColor = backgroundColor
34       }
35       if (imageUrl != null) {
36         config.imageUrl = imageUrl
37       }
38       return config
39     }
40 
41     private fun parseResizeMode(manifest: Manifest): SplashScreenImageResizeMode? {
42       val androidSplashInfo = manifest.getAndroidSplashInfo()
43       val rootSplashInfo = manifest.getRootSplashInfo()
44       val resizeMode = androidSplashInfo?.getNullable<String>(ExponentManifest.MANIFEST_SPLASH_RESIZE_MODE_KEY)
45         ?: rootSplashInfo?.getNullable(ExponentManifest.MANIFEST_SPLASH_RESIZE_MODE_KEY)
46       return SplashScreenImageResizeMode.fromString(resizeMode)
47     }
48 
49     private fun parseBackgroundColor(manifest: Manifest): Int? {
50       val androidSplashInfo = manifest.getAndroidSplashInfo()
51       val rootSplashInfo = manifest.getRootSplashInfo()
52       val backgroundColor = androidSplashInfo?.getNullable<String>(ExponentManifest.MANIFEST_SPLASH_BACKGROUND_COLOR_KEY)
53         ?: rootSplashInfo?.getNullable(ExponentManifest.MANIFEST_SPLASH_BACKGROUND_COLOR_KEY)
54 
55       return if (ColorParser.isValid(backgroundColor)) {
56         Color.parseColor(backgroundColor)
57       } else null
58     }
59 
60     /**
61      * Tries to retrieve imageUrl from the manifest checking for value for keys/paths in following order
62      * - android-scoped splash dpi images (starting from 'xxx-hdpi" and ending with 'mdpi')
63      * - android-scoped splash imageUrl
64      * - generic splash imageUrl
65      */
66     private fun parseImageUrl(manifest: Manifest): String? {
67       val androidSplash = manifest.getAndroidSplashInfo()
68       if (androidSplash != null) {
69         val dpiRelatedImageUrl = getStringFromJSONObject(
70           androidSplash,
71           *arrayOf(
72             "xxxhdpi", "xxhdpi", "xhdpi", "hdpi", "mdpi"
73           )
74             .map { s -> "${s}Url" }
75             .map { s -> arrayOf(s) }
76             .toTypedArray()
77         )
78         if (dpiRelatedImageUrl != null) {
79           return dpiRelatedImageUrl
80         }
81       }
82 
83       val androidSplashInfo = manifest.getAndroidSplashInfo()
84       val rootSplashInfo = manifest.getRootSplashInfo()
85       return androidSplashInfo?.getNullable(ExponentManifest.MANIFEST_SPLASH_IMAGE_URL_KEY)
86         ?: rootSplashInfo?.getNullable(ExponentManifest.MANIFEST_SPLASH_IMAGE_URL_KEY)
87     }
88 
89     private fun getStringFromJSONObject(jsonObject: JSONObject, vararg paths: Array<String>): String? {
90       for (path in paths) {
91         val pathResult = getStringFromJSONObject(jsonObject, path)
92         if (pathResult != null) {
93           return pathResult
94         }
95       }
96       return null
97     }
98 
99     private fun getStringFromJSONObject(jsonObject: JSONObject, path: Array<String>): String? {
100       var json: JSONObject? = jsonObject
101       for (i in path.indices) {
102         val isLastKey = i == path.size - 1
103         val key = path[i]
104         if (!json!!.has(key)) {
105           break
106         }
107         if (isLastKey) {
108           return json.getNullable(key)
109         }
110         json = json.optJSONObject(key)
111       }
112       return null
113     }
114   }
115 }
116