From f3eb4b982ea6a1586583516b94b2fe739fd21e9c Mon Sep 17 00:00:00 2001 From: davinci9196 Date: Tue, 26 Nov 2024 16:56:35 +0800 Subject: [PATCH 1/6] MainActivity: Add Javascript interactive content --- .../gms/accountsettings/ui/MainActivity.kt | 130 +++++++++++++++++- .../gms/accountsettings/ui/WebViewHelper.kt | 6 + 2 files changed, 131 insertions(+), 5 deletions(-) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt index 7040c9dbed..c48b6112dd 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt @@ -7,18 +7,20 @@ package org.microg.gms.accountsettings.ui import android.accounts.Account import android.accounts.AccountManager +import android.content.Intent import android.os.Bundle -import android.text.TextUtils import android.util.Log import android.view.View +import android.view.inputmethod.InputMethodManager +import android.webkit.JavascriptInterface import android.webkit.WebView -import android.widget.FrameLayout import android.widget.ProgressBar import android.widget.RelativeLayout import android.widget.RelativeLayout.LayoutParams.MATCH_PARENT import android.widget.RelativeLayout.LayoutParams.WRAP_CONTENT import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.updateLayoutParams +import org.json.JSONException +import org.json.JSONObject import org.microg.gms.auth.AuthConstants import org.microg.gms.common.Constants @@ -95,6 +97,7 @@ private val SCREEN_ID_TO_URL = hashMapOf( 10729 to "https://myaccount.google.com/data-and-privacy/data-visibility", 10759 to "https://myaccount.google.com/address/home", 10760 to "https://myaccount.google.com/address/work", + 14500 to "https://profilewidgets.google.com/alternate-profile/edit?interop=o&opts=sb", ) private val ALLOWED_WEB_PREFIXES = setOf( @@ -114,7 +117,8 @@ private val ALLOWED_WEB_PREFIXES = setOf( "https://fit.google.com/privacy/settings", "https://maps.google.com/maps/timeline", "https://myadcenter.google.com/controls", - "https://families.google.com/kidonboarding" + "https://families.google.com/kidonboarding", + "https://profilewidgets.google.com/alternate-profile/edit", ) private val ACTION_TO_SCREEN_ID = hashMapOf( @@ -126,6 +130,7 @@ private val ACTION_TO_SCREEN_ID = hashMapOf( class MainActivity : AppCompatActivity() { private lateinit var webView: WebView + private var accountName: String? = null private fun getSelectedAccountName(): String? = null @@ -146,7 +151,7 @@ class MainActivity : AppCompatActivity() { val callingPackage = intent?.getStringExtra(EXTRA_CALLING_PACKAGE_NAME) ?: callingActivity?.packageName ?: Constants.GMS_PACKAGE_NAME val ignoreAccount = intent?.getBooleanExtra(EXTRA_IGNORE_ACCOUNT, false) ?: false - val accountName = if (ignoreAccount) null else { + accountName = if (ignoreAccount) null else { val accounts = AccountManager.get(this).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE) val accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME) ?: intent.getParcelableExtra("account")?.name ?: getSelectedAccountName() accounts.find { it.name.equals(accountName) }?.name @@ -175,6 +180,7 @@ class MainActivity : AppCompatActivity() { webView = WebView(this).apply { layoutParams = RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) visibility = View.INVISIBLE + addJavascriptInterface(UiBridge(), "ocUi") } layout.addView(webView) setContentView(layout) @@ -198,4 +204,118 @@ class MainActivity : AppCompatActivity() { super.onBackPressed() } } + + private inner class UiBridge { + private var resultBundle: Bundle? = null + + @JavascriptInterface + fun close() { + Log.d(TAG, "close: ") + val intent = Intent() + if (resultBundle != null) { + intent.putExtras(resultBundle!!) + } + setResult(RESULT_OK, intent) + finish() + } + + @JavascriptInterface + fun closeWithResult(resultJsonStr: String?) { + Log.d(TAG, "closeWithResult: resultJsonStr -> $resultJsonStr") + setResult(resultJsonStr) + close() + } + + @JavascriptInterface + fun goBackOrClose() { + Log.d(TAG, "goBackOrClose: ") + onBackPressed() + } + + @JavascriptInterface + fun hideKeyboard() { + Log.d(TAG, "hideKeyboard: ") + val currentFocus = window.currentFocus + if (currentFocus != null) { + val inputMethodManager = this@MainActivity.getSystemService("input_method") as InputMethodManager? + inputMethodManager?.hideSoftInputFromWindow(currentFocus.windowToken, 0) + } + } + + @JavascriptInterface + fun isCloseWithResultSupported(): Boolean { + return true + } + + @JavascriptInterface + fun isOpenHelpEnabled(): Boolean { + return true + } + + @JavascriptInterface + fun isOpenScreenEnabled(): Boolean { + return true + } + + @JavascriptInterface + fun isSetResultSupported(): Boolean { + return true + } + + @JavascriptInterface + fun open(str: String?) { + Log.d(TAG, "open: str -> $str") + } + + @JavascriptInterface + fun openHelp(str: String?) { + Log.d(TAG, "openHelp: str -> $str") + } + + @JavascriptInterface + fun openScreen(screenId: Int, str: String?) { + Log.d(TAG, "openScreen: screenId -> $screenId str -> $str accountName -> $accountName") + val intent = Intent(this@MainActivity, MainActivity::class.java).apply { + putExtra(EXTRA_SCREEN_ID, screenId) + putExtra(EXTRA_ACCOUNT_NAME, accountName) + } + startActivity(intent) + } + + @JavascriptInterface + fun setBackStop() { + Log.d(TAG, "setBackStop: ") + webView.clearHistory() + } + + @JavascriptInterface + fun setResult(resultJsonStr: String?) { + Log.d(TAG, "setResult: resultJsonStr -> $resultJsonStr") + val map = jsonToMap(resultJsonStr) ?: return + resultBundle = Bundle().apply { + for ((key, value) in map) { + putString("result.$key", value) + } + } + } + + private fun jsonToMap(jsonStr: String?): Map? { + val hashMap = HashMap() + if (!jsonStr.isNullOrEmpty()) { + try { + val jSONObject = JSONObject(jsonStr) + val keys = jSONObject.keys() + while (keys.hasNext()) { + val next = keys.next() + val obj = jSONObject[next] + hashMap[next] = obj as String + } + } catch (e: JSONException) { + Log.d(TAG, "Unable to parse result JSON string", e) + return null + } + } + return hashMap + } + } } \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/WebViewHelper.kt b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/WebViewHelper.kt index 71bebf9f90..ffbbf45367 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/WebViewHelper.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/WebViewHelper.kt @@ -20,6 +20,7 @@ import androidx.webkit.WebViewClientCompat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.json.JSONObject import org.microg.gms.auth.AuthManager import org.microg.gms.common.Constants.GMS_PACKAGE_NAME import org.microg.gms.common.PackageUtils @@ -126,5 +127,10 @@ class WebViewHelper(private val activity: AppCompatActivity, private val webView settings.useWideViewPort = false settings.setSupportZoom(false) settings.javaScriptCanOpenWindowsAutomatically = false + settings.userAgentString = "${settings.userAgentString} ${ + String.format(Locale.getDefault(), "OcIdWebView (%s)", JSONObject().apply { + put("os", "Android") + }.toString()) + }" } } \ No newline at end of file From 1f77f97d9d21c3d9938adcb72df4695d3f1196d6 Mon Sep 17 00:00:00 2001 From: davinci9196 Date: Tue, 26 Nov 2024 17:48:00 +0800 Subject: [PATCH 2/6] cleanup --- .../kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt index c48b6112dd..0393c06fb5 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt @@ -235,11 +235,6 @@ class MainActivity : AppCompatActivity() { @JavascriptInterface fun hideKeyboard() { Log.d(TAG, "hideKeyboard: ") - val currentFocus = window.currentFocus - if (currentFocus != null) { - val inputMethodManager = this@MainActivity.getSystemService("input_method") as InputMethodManager? - inputMethodManager?.hideSoftInputFromWindow(currentFocus.windowToken, 0) - } } @JavascriptInterface From 79ae1056361233588265fe16f3ccfb54eddb2f31 Mon Sep 17 00:00:00 2001 From: davinci9196 Date: Fri, 6 Dec 2024 11:57:52 +0800 Subject: [PATCH 3/6] Synchronize the modified avatar to local --- .../org/microg/gms/people/PeopleManager.java | 12 ++++++++++++ .../gms/accountsettings/ui/MainActivity.kt | 18 ++++++++++++++++-- .../gms/accountsettings/ui/extensions.kt | 2 ++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/play-services-core/src/main/java/org/microg/gms/people/PeopleManager.java b/play-services-core/src/main/java/org/microg/gms/people/PeopleManager.java index e6ea7dbf80..0323c81407 100644 --- a/play-services-core/src/main/java/org/microg/gms/people/PeopleManager.java +++ b/play-services-core/src/main/java/org/microg/gms/people/PeopleManager.java @@ -20,6 +20,7 @@ import android.content.ContentValues; import android.content.Context; import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Log; @@ -114,6 +115,17 @@ public static Bitmap getOwnerAvatarBitmap(Context context, String accountName, b return BitmapFactory.decodeFile(avaterFile.getPath()); } + public static void updateOwnerAvatar(Context context, String accountName, String newAvatar) { + try (DatabaseHelper databaseHelper = new DatabaseHelper(context); SQLiteDatabase db = databaseHelper.getWritableDatabase()) { + ContentValues contentValues = new ContentValues(); + contentValues.put("avatar", newAvatar); + int rowsAffected = db.update(DatabaseHelper.OWNERS_TABLE, contentValues, "account_name = ?", new String[]{accountName}); + Log.d(TAG, "updateOwnerAvatar affected: " + rowsAffected); + } catch (Exception e) { + Log.e(TAG, "Error updating avatar: " + e.getMessage()); + } + } + public static String loadUserInfo(Context context, Account account) { try { URLConnection conn = new URL(USERINFO_URL).openConnection(); diff --git a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt index 0393c06fb5..e4e70545f7 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt @@ -9,9 +9,9 @@ import android.accounts.Account import android.accounts.AccountManager import android.content.Intent import android.os.Bundle +import android.text.TextUtils import android.util.Log import android.view.View -import android.view.inputmethod.InputMethodManager import android.webkit.JavascriptInterface import android.webkit.WebView import android.widget.ProgressBar @@ -19,10 +19,12 @@ import android.widget.RelativeLayout import android.widget.RelativeLayout.LayoutParams.MATCH_PARENT import android.widget.RelativeLayout.LayoutParams.WRAP_CONTENT import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope import org.json.JSONException import org.json.JSONObject import org.microg.gms.auth.AuthConstants import org.microg.gms.common.Constants +import org.microg.gms.people.PeopleManager private const val TAG = "AccountSettings" @@ -131,6 +133,7 @@ private val ACTION_TO_SCREEN_ID = hashMapOf( class MainActivity : AppCompatActivity() { private lateinit var webView: WebView private var accountName: String? = null + private var resultBundle: Bundle? = null private fun getSelectedAccountName(): String? = null @@ -205,8 +208,16 @@ class MainActivity : AppCompatActivity() { } } + private fun updateLocalAccountAvatar(newAvatarUrl: String?) { + if (TextUtils.isEmpty(newAvatarUrl) || accountName == null) { + return + } + lifecycleScope.launchWhenCreated { + PeopleManager.updateOwnerAvatar(this@MainActivity, accountName, newAvatarUrl) + } + } + private inner class UiBridge { - private var resultBundle: Bundle? = null @JavascriptInterface fun close() { @@ -287,6 +298,9 @@ class MainActivity : AppCompatActivity() { fun setResult(resultJsonStr: String?) { Log.d(TAG, "setResult: resultJsonStr -> $resultJsonStr") val map = jsonToMap(resultJsonStr) ?: return + if (map.containsKey(KEY_UPDATED_PHOTO_URL)) { + updateLocalAccountAvatar(map[KEY_UPDATED_PHOTO_URL]) + } resultBundle = Bundle().apply { for ((key, value) in map) { putString("result.$key", value) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/extensions.kt b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/extensions.kt index 30a3b01be9..d1850ea56e 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/extensions.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/extensions.kt @@ -22,4 +22,6 @@ const val EXTRA_THEME_CHOICE = "extra.themeChoice" const val EXTRA_SCREEN_MY_ACTIVITY_PRODUCT = "extra.screen.myactivityProduct" const val EXTRA_SCREEN_KID_ONBOARDING_PARAMS = "extra.screen.kidOnboardingParams" +const val KEY_UPDATED_PHOTO_URL = "updatedPhotoUrl" + const val OPTION_SCREEN_FLAVOR = "screenFlavor" \ No newline at end of file From 98fa31bab063df0fa922c443c252ba3edc9f08c7 Mon Sep 17 00:00:00 2001 From: davinci9196 Date: Fri, 6 Dec 2024 14:59:25 +0800 Subject: [PATCH 4/6] Fixed the abnormal display of avatar on the account page of MG Setting Center --- .../src/main/kotlin/org/microg/gms/ui/AccountsFragment.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/AccountsFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/AccountsFragment.kt index e0039366b8..38be3c0e0e 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/AccountsFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/AccountsFragment.kt @@ -53,7 +53,9 @@ class AccountsFragment : PreferenceFragmentCompat() { } private fun getCircleBitmapDrawable(bitmap: Bitmap?) = - if (bitmap != null) RoundedBitmapDrawableFactory.create(resources, bitmap).also { it.isCircular = true } else null + if (bitmap != null) RoundedBitmapDrawableFactory.create(resources, bitmap.let { + Bitmap.createScaledBitmap(bitmap, 160, 160, true) + }).also { it.isCircular = true } else null override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.preferences_accounts) From 42d990bf7cf780c547f76b750eaf4bfcf745c024 Mon Sep 17 00:00:00 2001 From: davinci9196 Date: Fri, 6 Dec 2024 16:12:44 +0800 Subject: [PATCH 5/6] Switching threads --- .../org/microg/gms/accountsettings/ui/MainActivity.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt index e4e70545f7..3509ab0b9f 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt @@ -20,6 +20,8 @@ import android.widget.RelativeLayout.LayoutParams.MATCH_PARENT import android.widget.RelativeLayout.LayoutParams.WRAP_CONTENT import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import org.json.JSONException import org.json.JSONObject import org.microg.gms.auth.AuthConstants @@ -213,7 +215,9 @@ class MainActivity : AppCompatActivity() { return } lifecycleScope.launchWhenCreated { - PeopleManager.updateOwnerAvatar(this@MainActivity, accountName, newAvatarUrl) + withContext(Dispatchers.IO) { + PeopleManager.updateOwnerAvatar(this@MainActivity, accountName, newAvatarUrl) + } } } From eb73ffd7a2897dc86160f5913da13bb081a20b2a Mon Sep 17 00:00:00 2001 From: davinci9196 Date: Fri, 6 Dec 2024 16:27:19 +0800 Subject: [PATCH 6/6] Adjust the size of the avatar --- .../src/main/kotlin/org/microg/gms/ui/AccountsFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/AccountsFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/AccountsFragment.kt index 38be3c0e0e..a5dc94efd5 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/AccountsFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/AccountsFragment.kt @@ -54,7 +54,7 @@ class AccountsFragment : PreferenceFragmentCompat() { private fun getCircleBitmapDrawable(bitmap: Bitmap?) = if (bitmap != null) RoundedBitmapDrawableFactory.create(resources, bitmap.let { - Bitmap.createScaledBitmap(bitmap, 160, 160, true) + Bitmap.createScaledBitmap(bitmap, 100, 100, true) }).also { it.isCircular = true } else null override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {