@@ -7,20 +7,26 @@ package org.microg.gms.accountsettings.ui
77
88import android.accounts.Account
99import android.accounts.AccountManager
10+ import android.content.Intent
1011import android.os.Bundle
1112import android.text.TextUtils
1213import android.util.Log
1314import android.view.View
15+ import android.webkit.JavascriptInterface
1416import android.webkit.WebView
15- import android.widget.FrameLayout
1617import android.widget.ProgressBar
1718import android.widget.RelativeLayout
1819import android.widget.RelativeLayout.LayoutParams.MATCH_PARENT
1920import android.widget.RelativeLayout.LayoutParams.WRAP_CONTENT
2021import androidx.appcompat.app.AppCompatActivity
21- import androidx.core.view.updateLayoutParams
22+ import androidx.lifecycle.lifecycleScope
23+ import kotlinx.coroutines.Dispatchers
24+ import kotlinx.coroutines.withContext
25+ import org.json.JSONException
26+ import org.json.JSONObject
2227import org.microg.gms.auth.AuthConstants
2328import org.microg.gms.common.Constants
29+ import org.microg.gms.people.PeopleManager
2430
2531private const val TAG = " AccountSettings"
2632
@@ -96,6 +102,7 @@ private val SCREEN_ID_TO_URL = hashMapOf(
96102 10729 to " https://myaccount.google.com/data-and-privacy/data-visibility" ,
97103 10759 to " https://myaccount.google.com/address/home" ,
98104 10760 to " https://myaccount.google.com/address/work" ,
105+ 14500 to " https://profilewidgets.google.com/alternate-profile/edit?interop=o&opts=sb" ,
99106)
100107
101108private val ALLOWED_WEB_PREFIXES = setOf (
@@ -115,7 +122,8 @@ private val ALLOWED_WEB_PREFIXES = setOf(
115122 " https://fit.google.com/privacy/settings" ,
116123 " https://maps.google.com/maps/timeline" ,
117124 " https://myadcenter.google.com/controls" ,
118- " https://families.google.com/kidonboarding"
125+ " https://families.google.com/kidonboarding" ,
126+ " https://profilewidgets.google.com/alternate-profile/edit" ,
119127)
120128
121129private val ACTION_TO_SCREEN_ID = hashMapOf(
@@ -126,6 +134,8 @@ private val ACTION_TO_SCREEN_ID = hashMapOf(
126134
127135class MainActivity : AppCompatActivity () {
128136 private lateinit var webView: WebView
137+ private var accountName: String? = null
138+ private var resultBundle: Bundle ? = null
129139
130140 private fun getSelectedAccountName (): String? = null
131141
@@ -146,7 +156,7 @@ class MainActivity : AppCompatActivity() {
146156 val callingPackage = intent?.getStringExtra(EXTRA_CALLING_PACKAGE_NAME ) ? : callingActivity?.packageName ? : Constants .GMS_PACKAGE_NAME
147157
148158 val ignoreAccount = intent?.getBooleanExtra(EXTRA_IGNORE_ACCOUNT , false ) ? : false
149- val accountName = if (ignoreAccount) null else {
159+ accountName = if (ignoreAccount) null else {
150160 val accounts = AccountManager .get(this ).getAccountsByType(AuthConstants .DEFAULT_ACCOUNT_TYPE )
151161 val accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME ) ? : intent.getParcelableExtra<Account >(" account" )?.name ? : getSelectedAccountName()
152162 accounts.find { it.name.equals(accountName) }?.name
@@ -175,6 +185,7 @@ class MainActivity : AppCompatActivity() {
175185 webView = WebView (this ).apply {
176186 layoutParams = RelativeLayout .LayoutParams (MATCH_PARENT , MATCH_PARENT )
177187 visibility = View .INVISIBLE
188+ addJavascriptInterface(UiBridge (), " ocUi" )
178189 }
179190 layout.addView(webView)
180191 setContentView(layout)
@@ -198,4 +209,126 @@ class MainActivity : AppCompatActivity() {
198209 super .onBackPressed()
199210 }
200211 }
212+
213+ private fun updateLocalAccountAvatar (newAvatarUrl : String? ) {
214+ if (TextUtils .isEmpty(newAvatarUrl) || accountName == null ) {
215+ return
216+ }
217+ lifecycleScope.launchWhenCreated {
218+ withContext(Dispatchers .IO ) {
219+ PeopleManager .updateOwnerAvatar(this @MainActivity, accountName, newAvatarUrl)
220+ }
221+ }
222+ }
223+
224+ private inner class UiBridge {
225+
226+ @JavascriptInterface
227+ fun close () {
228+ Log .d(TAG , " close: " )
229+ val intent = Intent ()
230+ if (resultBundle != null ) {
231+ intent.putExtras(resultBundle!! )
232+ }
233+ setResult(RESULT_OK , intent)
234+ finish()
235+ }
236+
237+ @JavascriptInterface
238+ fun closeWithResult (resultJsonStr : String? ) {
239+ Log .d(TAG , " closeWithResult: resultJsonStr -> $resultJsonStr " )
240+ setResult(resultJsonStr)
241+ close()
242+ }
243+
244+ @JavascriptInterface
245+ fun goBackOrClose () {
246+ Log .d(TAG , " goBackOrClose: " )
247+ onBackPressed()
248+ }
249+
250+ @JavascriptInterface
251+ fun hideKeyboard () {
252+ Log .d(TAG , " hideKeyboard: " )
253+ }
254+
255+ @JavascriptInterface
256+ fun isCloseWithResultSupported (): Boolean {
257+ return true
258+ }
259+
260+ @JavascriptInterface
261+ fun isOpenHelpEnabled (): Boolean {
262+ return true
263+ }
264+
265+ @JavascriptInterface
266+ fun isOpenScreenEnabled (): Boolean {
267+ return true
268+ }
269+
270+ @JavascriptInterface
271+ fun isSetResultSupported (): Boolean {
272+ return true
273+ }
274+
275+ @JavascriptInterface
276+ fun open (str : String? ) {
277+ Log .d(TAG , " open: str -> $str " )
278+ }
279+
280+ @JavascriptInterface
281+ fun openHelp (str : String? ) {
282+ Log .d(TAG , " openHelp: str -> $str " )
283+ }
284+
285+ @JavascriptInterface
286+ fun openScreen (screenId : Int , str : String? ) {
287+ Log .d(TAG , " openScreen: screenId -> $screenId str -> $str accountName -> $accountName " )
288+ val intent = Intent (this @MainActivity, MainActivity ::class .java).apply {
289+ putExtra(EXTRA_SCREEN_ID , screenId)
290+ putExtra(EXTRA_ACCOUNT_NAME , accountName)
291+ }
292+ startActivity(intent)
293+ }
294+
295+ @JavascriptInterface
296+ fun setBackStop () {
297+ Log .d(TAG , " setBackStop: " )
298+ webView.clearHistory()
299+ }
300+
301+ @JavascriptInterface
302+ fun setResult (resultJsonStr : String? ) {
303+ Log .d(TAG , " setResult: resultJsonStr -> $resultJsonStr " )
304+ val map = jsonToMap(resultJsonStr) ? : return
305+ if (map.containsKey(KEY_UPDATED_PHOTO_URL )) {
306+ updateLocalAccountAvatar(map[KEY_UPDATED_PHOTO_URL ])
307+ }
308+ resultBundle = Bundle ().apply {
309+ for ((key, value) in map) {
310+ putString(" result.$key " , value)
311+ }
312+ }
313+ }
314+
315+ private fun jsonToMap (jsonStr : String? ): Map <String , String >? {
316+ val hashMap = HashMap <String , String >()
317+ if (! jsonStr.isNullOrEmpty()) {
318+ try {
319+ val jSONObject = JSONObject (jsonStr)
320+ val keys = jSONObject.keys()
321+ while (keys.hasNext()) {
322+ val next = keys.next()
323+ val obj = jSONObject[next]
324+ hashMap[next] = obj as String
325+ }
326+ } catch (e: JSONException ) {
327+ Log .d(TAG , " Unable to parse result JSON string" , e)
328+ return null
329+ }
330+ }
331+ return hashMap
332+ }
333+ }
201334}
0 commit comments