<lambda>null1 package expo.modules.devlauncher.launcher
2 
3 import android.content.Context
4 import android.content.SharedPreferences
5 import android.net.Uri
6 import com.google.gson.Gson
7 import expo.modules.manifests.core.Manifest
8 
9 private const val RECENTLY_OPENED_APPS_SHARED_PREFERENCES = "expo.modules.devlauncher.recentyopenedapps"
10 
11 private const val TIME_TO_REMOVE = 1000 * 60 * 60 * 24 * 3 // 3 days
12 
13 data class DevLauncherAppEntry(
14   val timestamp: Long,
15   val name: String?,
16   val url: String?,
17   val isEASUpdate: Boolean?,
18   val updateMessage: String?,
19   val branchName: String?
20 )
21 
22 class DevLauncherRecentlyOpenedAppsRegistry(context: Context) {
23   private val sharedPreferences: SharedPreferences = context.getSharedPreferences(RECENTLY_OPENED_APPS_SHARED_PREFERENCES, Context.MODE_PRIVATE)
24 
25   fun appWasOpened(url: String, queryParams: Map<String, String>, manifest: Manifest?) {
26     var appEntry = mutableMapOf<String, Any>()
27     val uri = Uri.parse(url)
28 
29     if (sharedPreferences.contains(url)) {
30       val previousEntryJsonString = sharedPreferences.getString(url, null)
31       val previousEntry = Gson().fromJson(previousEntryJsonString, Map::class.java)
32       appEntry = previousEntry.toMutableMap() as MutableMap<String, Any>
33     }
34 
35     val timestamp = TimeHelper.getCurrentTime()
36 
37     val isEASUpdate = uri.host === "u.expo.dev" || uri.host == "staging-u.expo.dev"
38     appEntry["isEASUpdate"] = isEASUpdate
39 
40     if (isEASUpdate) {
41       if (queryParams["updateMessage"] != null) {
42         appEntry["updateMessage"] = queryParams["updateMessage"] as String
43       }
44     }
45 
46     if (manifest != null) {
47       appEntry["name"] = manifest.getName() as String
48 
49       // TODO - expose metadata object in expo-manifests
50       val json = manifest.getRawJson()
51 
52       if (isEASUpdate) {
53         val metadata = json.getJSONObject("metadata")
54         appEntry["branchName"] = metadata["branchName"] ?: ""
55       }
56     }
57 
58     appEntry["timestamp"] = timestamp
59     appEntry["url"] = url
60 
61     sharedPreferences
62       .edit()
63       .putString(url, Gson().toJson(appEntry))
64       .apply()
65   }
66 
67   fun getRecentlyOpenedApps(): List<DevLauncherAppEntry> {
68     val result = mutableListOf<DevLauncherAppEntry>()
69     val toRemove = mutableListOf<String>()
70     val gson = Gson()
71 
72     sharedPreferences.all.forEach { (url, appEntryString) ->
73       val appEntry = gson.fromJson(appEntryString as String, DevLauncherAppEntry::class.java)
74       if (TimeHelper.getCurrentTime() - appEntry.timestamp > TIME_TO_REMOVE) {
75         toRemove.add(url)
76         return@forEach
77       }
78 
79       result.add(appEntry)
80     }
81 
82     sharedPreferences.edit().apply {
83       toRemove.forEach {
84         remove(it)
85       }
86     }.apply()
87 
88     return result
89   }
90 
91   fun getMostRecentApp(): DevLauncherAppEntry? {
92     val recentlyOpenedApps = getRecentlyOpenedApps()
93 
94     return if (recentlyOpenedApps.isNotEmpty()) {
95       recentlyOpenedApps.maxByOrNull { it.timestamp }
96     } else {
97       null
98     }
99   }
100 
101   fun clearRegistry() {
102     sharedPreferences.edit().clear().apply()
103   }
104 
105   object TimeHelper {
106     fun getCurrentTime() = System.currentTimeMillis()
107   }
108 }
109