From d97a1ea32bbe5e1e41c76a89e404d1d675bed269 Mon Sep 17 00:00:00 2001 From: Cuynu Date: Sat, 11 May 2024 07:46:07 +0000 Subject: [PATCH 01/29] hide open YouTube Vanced+ options until its first release --- .../src/main/res/xml/preferences_google_more.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/play-services-core/src/main/res/xml/preferences_google_more.xml b/play-services-core/src/main/res/xml/preferences_google_more.xml index 65a3c7e4..c018f3a7 100755 --- a/play-services-core/src/main/res/xml/preferences_google_more.xml +++ b/play-services-core/src/main/res/xml/preferences_google_more.xml @@ -75,7 +75,7 @@ android:title="@string/pref_auth_include_android_id_title"/> + android:summary="DD MM YYYY - nightly"> From ec9a57224f4b322491354ef756b7d3c58d51aa6e Mon Sep 17 00:00:00 2001 From: Cuynu Date: Mon, 29 Jul 2024 10:09:51 +0000 Subject: [PATCH 02/29] bump 24.28.34 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0ef88b7d..d7fe9a96 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ buildscript { } -def gmsVersion = "24.17.17" +def gmsVersion = "24.28.34" def gmsVersionCode = Integer.parseInt(gmsVersion.replaceAll('\\.', '')) def ourVersionBase = "0.3.0" From ee29d87c72148cea462867e4cac53138176bf0b6 Mon Sep 17 00:00:00 2001 From: Cuynu Date: Mon, 29 Jul 2024 10:13:16 +0000 Subject: [PATCH 03/29] . --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 90b361b6..29f47891 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This fork tweaks MicroG to be usable by applications that require Google authentication such as [YouTube Vanced+](https://gitlab.com/cuynu/vancedx). ## Warning! -Vanced+ microG probably does not works in ReVanced/RVX in future as recent changes from ReVanced/RVX to use with they specific MicroG called ReVanced MicroG with different package name ! +Vanced+ microG are currently **DOES NOT WORK** with ReVanced/RVX as they now uses their own ReVanced microG with specific package name! However, there are workaround : [Issues #15](https://gitlab.com/cuynu/VancedxMicroG/-/issues/15#note_1837372638) ## Notable changes From 8eec459e70de9f0fd9d87d0a9c677025aeaf6a8b Mon Sep 17 00:00:00 2001 From: Cuynu Date: Thu, 8 Aug 2024 14:08:42 +0700 Subject: [PATCH 04/29] update gradle 8.0.0 --- build.gradle | 2 +- fake-signature/build.gradle | 4 ++-- gradle.properties | 4 +++- gradle/wrapper/gradle-wrapper.properties | 2 +- play-services-api/build.gradle | 8 ++++++-- play-services-api/src/main/AndroidManifest.xml | 2 +- play-services-base-api/build.gradle | 8 ++++++-- play-services-base-api/src/main/AndroidManifest.xml | 2 +- play-services-base-core/build.gradle | 6 +++--- play-services-base-core/src/main/AndroidManifest.xml | 3 +-- play-services-base/build.gradle | 5 +++-- play-services-base/src/main/AndroidManifest.xml | 3 +-- play-services-basement/build.gradle | 6 ++++-- play-services-basement/src/main/AndroidManifest.xml | 2 +- play-services-core-proto/build.gradle | 4 ++-- play-services-core/build.gradle | 4 ++-- play-services-core/microg-ui-tools/build.gradle | 5 +++-- .../microg-ui-tools/src/main/AndroidManifest.xml | 2 +- play-services-iid-api/build.gradle | 8 ++++++-- play-services-iid-api/src/main/AndroidManifest.xml | 2 +- play-services-tasks/build.gradle | 5 +++-- play-services-tasks/src/main/AndroidManifest.xml | 2 +- 22 files changed, 53 insertions(+), 36 deletions(-) diff --git a/build.gradle b/build.gradle index d7fe9a96..60699d2e 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ buildscript { ext.wireVersion = '4.8.0' - ext.androidBuildGradleVersion = '7.4.2' + ext.androidBuildGradleVersion = '8.0.0' ext.androidBuildVersionTools = '33.0.2' ext.androidMinSdk = 23 diff --git a/fake-signature/build.gradle b/fake-signature/build.gradle index 19f0fc40..e04d9893 100644 --- a/fake-signature/build.gradle +++ b/fake-signature/build.gradle @@ -17,8 +17,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } } diff --git a/gradle.properties b/gradle.properties index 976747da..126b7d28 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,5 @@ android.useAndroidX=true -android.disableAutomaticComponentCreation=true org.gradle.jvmargs=-Xmx2048m -XX:+UseParallelGC +android.defaults.buildfeatures.buildconfig=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b1624c47..42defcc9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/play-services-api/build.gradle b/play-services-api/build.gradle index e254f48d..20d8bea5 100644 --- a/play-services-api/build.gradle +++ b/play-services-api/build.gradle @@ -26,9 +26,13 @@ android { } compileOptions { - sourceCompatibility = 1.8 - targetCompatibility = 1.8 + sourceCompatibility = 17 + targetCompatibility = 17 } + buildFeatures { + aidl true + } + namespace 'org.microg.gms.api' } dependencies { diff --git a/play-services-api/src/main/AndroidManifest.xml b/play-services-api/src/main/AndroidManifest.xml index d4a4d07a..359a9b71 100644 --- a/play-services-api/src/main/AndroidManifest.xml +++ b/play-services-api/src/main/AndroidManifest.xml @@ -15,4 +15,4 @@ ~ limitations under the License. --> - + diff --git a/play-services-base-api/build.gradle b/play-services-base-api/build.gradle index b806da4c..23b6b07c 100644 --- a/play-services-base-api/build.gradle +++ b/play-services-base-api/build.gradle @@ -34,7 +34,11 @@ android { } compileOptions { - sourceCompatibility = 1.8 - targetCompatibility = 1.8 + sourceCompatibility = 17 + targetCompatibility = 17 } + buildFeatures { + aidl true + } + namespace 'org.microg.gms.base.api' } \ No newline at end of file diff --git a/play-services-base-api/src/main/AndroidManifest.xml b/play-services-base-api/src/main/AndroidManifest.xml index 7c8eeef3..055d07d5 100644 --- a/play-services-base-api/src/main/AndroidManifest.xml +++ b/play-services-base-api/src/main/AndroidManifest.xml @@ -3,4 +3,4 @@ ~ SPDX-FileCopyrightText: 2020, microG Project Team ~ SPDX-License-Identifier: Apache-2.0 --> - + diff --git a/play-services-base-core/build.gradle b/play-services-base-core/build.gradle index ad962700..34288f21 100644 --- a/play-services-base-core/build.gradle +++ b/play-services-base-core/build.gradle @@ -21,7 +21,6 @@ android { buildToolsVersion androidBuildVersionTools defaultConfig { - versionName version minSdkVersion androidMinSdk targetSdkVersion androidTargetSdk @@ -33,7 +32,8 @@ android { } compileOptions { - sourceCompatibility = 1.8 - targetCompatibility = 1.8 + sourceCompatibility = 17 + targetCompatibility = 17 } + namespace 'org.microg.gms.base.core' } \ No newline at end of file diff --git a/play-services-base-core/src/main/AndroidManifest.xml b/play-services-base-core/src/main/AndroidManifest.xml index 39554ca3..5c321135 100644 --- a/play-services-base-core/src/main/AndroidManifest.xml +++ b/play-services-base-core/src/main/AndroidManifest.xml @@ -4,8 +4,7 @@ ~ SPDX-License-Identifier: Apache-2.0 --> + xmlns:android="http://schemas.android.com/apk/res/android"> - + - + diff --git a/play-services-core-proto/build.gradle b/play-services-core-proto/build.gradle index 2cfb351e..6edfcb4b 100644 --- a/play-services-core-proto/build.gradle +++ b/play-services-core-proto/build.gradle @@ -21,9 +21,9 @@ sourceSets { } compileKotlin { - kotlinOptions.jvmTarget = 1.8 + kotlinOptions.jvmTarget = 17 } compileTestKotlin { - kotlinOptions.jvmTarget = 1.8 + kotlinOptions.jvmTarget = 17 } \ No newline at end of file diff --git a/play-services-core/build.gradle b/play-services-core/build.gradle index 5cb9aedd..a9d2351a 100644 --- a/play-services-core/build.gradle +++ b/play-services-core/build.gradle @@ -109,8 +109,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } packagingOptions { diff --git a/play-services-core/microg-ui-tools/build.gradle b/play-services-core/microg-ui-tools/build.gradle index b6b2018d..260aa6a5 100644 --- a/play-services-core/microg-ui-tools/build.gradle +++ b/play-services-core/microg-ui-tools/build.gradle @@ -28,14 +28,15 @@ android { } compileOptions { - sourceCompatibility = 1.8 - targetCompatibility = 1.8 + sourceCompatibility = 17 + targetCompatibility = 17 } lintOptions { // TODO: Remove MissingTranslation once we have stable strings and proper translations. disable 'MissingTranslation', 'GetLocales' } + namespace 'org.microg.tools.ui' } dependencies { diff --git a/play-services-core/microg-ui-tools/src/main/AndroidManifest.xml b/play-services-core/microg-ui-tools/src/main/AndroidManifest.xml index 004f299c..359a9b71 100644 --- a/play-services-core/microg-ui-tools/src/main/AndroidManifest.xml +++ b/play-services-core/microg-ui-tools/src/main/AndroidManifest.xml @@ -15,4 +15,4 @@ ~ limitations under the License. --> - + diff --git a/play-services-iid-api/build.gradle b/play-services-iid-api/build.gradle index 603c53b4..34ed3abb 100644 --- a/play-services-iid-api/build.gradle +++ b/play-services-iid-api/build.gradle @@ -26,9 +26,13 @@ android { } compileOptions { - sourceCompatibility = 1.8 - targetCompatibility = 1.8 + sourceCompatibility = 17 + targetCompatibility = 17 } + buildFeatures { + aidl true + } + namespace 'org.microg.gms.iid.api' } dependencies { diff --git a/play-services-iid-api/src/main/AndroidManifest.xml b/play-services-iid-api/src/main/AndroidManifest.xml index e979258e..ca617cfb 100644 --- a/play-services-iid-api/src/main/AndroidManifest.xml +++ b/play-services-iid-api/src/main/AndroidManifest.xml @@ -15,4 +15,4 @@ ~ limitations under the License. --> - \ No newline at end of file + \ No newline at end of file diff --git a/play-services-tasks/build.gradle b/play-services-tasks/build.gradle index 0eb84bbf..068aeb92 100644 --- a/play-services-tasks/build.gradle +++ b/play-services-tasks/build.gradle @@ -22,9 +22,10 @@ android { } compileOptions { - sourceCompatibility = 1.8 - targetCompatibility = 1.8 + sourceCompatibility = 17 + targetCompatibility = 17 } + namespace 'org.microg.gms.tasks' } dependencies { diff --git a/play-services-tasks/src/main/AndroidManifest.xml b/play-services-tasks/src/main/AndroidManifest.xml index c7b833fe..c256eb44 100644 --- a/play-services-tasks/src/main/AndroidManifest.xml +++ b/play-services-tasks/src/main/AndroidManifest.xml @@ -4,4 +4,4 @@ ~ SPDX-License-Identifier: Apache-2.0 --> - + From fccdc9c28829b9f4f5c8244d66f198644edaec50 Mon Sep 17 00:00:00 2001 From: cuynu Date: Thu, 26 Sep 2024 23:17:21 +0700 Subject: [PATCH 05/29] add new profile --- .../src/main/res/xml/profile_bullhead_27.xml | 36 ------------------ .../src/main/res/xml/profile_googlevr.xml | 31 ++++++++++++++++ .../res/xml/profile_lineage_falcon_25.xml | 36 ------------------ .../res/xml/profile_lineage_xperiaxz2.xml | 34 +++++++++++++++++ .../src/main/res/xml/profile_redfin_33.xml | 37 ------------------- .../xml/profile_sdk_gphone64_x86_64_33.xml | 37 ------------------- 6 files changed, 65 insertions(+), 146 deletions(-) delete mode 100644 play-services-core/src/main/res/xml/profile_bullhead_27.xml create mode 100644 play-services-core/src/main/res/xml/profile_googlevr.xml delete mode 100644 play-services-core/src/main/res/xml/profile_lineage_falcon_25.xml create mode 100644 play-services-core/src/main/res/xml/profile_lineage_xperiaxz2.xml delete mode 100644 play-services-core/src/main/res/xml/profile_redfin_33.xml delete mode 100644 play-services-core/src/main/res/xml/profile_sdk_gphone64_x86_64_33.xml diff --git a/play-services-core/src/main/res/xml/profile_bullhead_27.xml b/play-services-core/src/main/res/xml/profile_bullhead_27.xml deleted file mode 100644 index 186a4356..00000000 --- a/play-services-core/src/main/res/xml/profile_bullhead_27.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/play-services-core/src/main/res/xml/profile_googlevr.xml b/play-services-core/src/main/res/xml/profile_googlevr.xml new file mode 100644 index 00000000..1d0c7fba --- /dev/null +++ b/play-services-core/src/main/res/xml/profile_googlevr.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/play-services-core/src/main/res/xml/profile_lineage_falcon_25.xml b/play-services-core/src/main/res/xml/profile_lineage_falcon_25.xml deleted file mode 100644 index 57beb5d4..00000000 --- a/play-services-core/src/main/res/xml/profile_lineage_falcon_25.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/play-services-core/src/main/res/xml/profile_lineage_xperiaxz2.xml b/play-services-core/src/main/res/xml/profile_lineage_xperiaxz2.xml new file mode 100644 index 00000000..6aa36bfa --- /dev/null +++ b/play-services-core/src/main/res/xml/profile_lineage_xperiaxz2.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/play-services-core/src/main/res/xml/profile_redfin_33.xml b/play-services-core/src/main/res/xml/profile_redfin_33.xml deleted file mode 100644 index 52c57f88..00000000 --- a/play-services-core/src/main/res/xml/profile_redfin_33.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/play-services-core/src/main/res/xml/profile_sdk_gphone64_x86_64_33.xml b/play-services-core/src/main/res/xml/profile_sdk_gphone64_x86_64_33.xml deleted file mode 100644 index b616c365..00000000 --- a/play-services-core/src/main/res/xml/profile_sdk_gphone64_x86_64_33.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 195673c14bd5709395e4b5f62acf60f0768fed75 Mon Sep 17 00:00:00 2001 From: cuynu Date: Thu, 26 Sep 2024 23:17:58 +0700 Subject: [PATCH 06/29] show serial --- .../main/res/xml/preferences_device_registration.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/play-services-core/src/main/res/xml/preferences_device_registration.xml b/play-services-core/src/main/res/xml/preferences_device_registration.xml index ecd4b469..91c35133 100755 --- a/play-services-core/src/main/res/xml/preferences_device_registration.xml +++ b/play-services-core/src/main/res/xml/preferences_device_registration.xml @@ -13,16 +13,16 @@ android:key="pref_device_profile" android:persistent="false" android:title="@string/profile_name" - tools:summary="Automatic (Google Pixel 3, Android 11)" /> + tools:summary="Automatic" /> + tools:summary="" /> + tools:summary="Last registration: XX hours ago" /> + tools:summary="" /> Date: Thu, 26 Sep 2024 23:19:37 +0700 Subject: [PATCH 07/29] set FlAG_IMMUTABLE flag --- .../src/main/java/org/microg/gms/gcm/McsService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java b/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java index f4766b4a..343d1721 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java @@ -209,7 +209,7 @@ public class McsService extends Service implements Handler.Callback { super.onCreate(); TriggerReceiver.register(this); database = new GcmDatabase(this); - heartbeatIntent = PendingIntent.getService(this, 0, new Intent(ACTION_HEARTBEAT, null, this, McsService.class), 0); + heartbeatIntent = PendingIntent.getService(this, 0, new Intent(ACTION_HEARTBEAT, null, this, McsService.class), PendingIntent.FLAG_IMMUTABLE); alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); powerManager = (PowerManager) getSystemService(POWER_SERVICE); if (checkSelfPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") == PackageManager.PERMISSION_GRANTED) { @@ -300,7 +300,7 @@ public class McsService extends Service implements Handler.Callback { AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE); long delay = getCurrentDelay(); logd(context, "Scheduling reconnect in " + delay / 1000 + " seconds..."); - PendingIntent pi = PendingIntent.getBroadcast(context, 1, new Intent(ACTION_RECONNECT, null, context, TriggerReceiver.class), 0); + PendingIntent pi = PendingIntent.getBroadcast(context, 1, new Intent(ACTION_RECONNECT, null, context, TriggerReceiver.class), PendingIntent.FLAG_IMMUTABLE); alarmManager.setExactAndAllowWhileIdle(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delay, pi); } From 81ea45af34edb0fde37ed2e1e65525e50785123e Mon Sep 17 00:00:00 2001 From: cuynu Date: Thu, 26 Sep 2024 23:20:02 +0700 Subject: [PATCH 08/29] android id must be visible --- .../org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt index a0b4ad13..ec274c5e 100755 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt @@ -153,7 +153,7 @@ class DeviceRegistrationPreferencesFragment : PreferenceFragmentCompat() { androidId.summary = serviceInfo.androidId.toString(16) } else { status.summary = getString(R.string.checkin_not_registered) - androidId.isVisible = false + androidId.isVisible = true } } } From 320320c24a4545757823d5eeaa284519ad35d1f8 Mon Sep 17 00:00:00 2001 From: cuynu Date: Thu, 26 Sep 2024 23:20:33 +0700 Subject: [PATCH 09/29] set FLAG_IMMUTABLE flag --- .../src/main/java/org/microg/gms/checkin/CheckinService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinService.java b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinService.java index bd5bfabb..8f00098f 100755 --- a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinService.java +++ b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinService.java @@ -124,7 +124,7 @@ public class CheckinService extends IntentService { static void schedule(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - PendingIntent pendingIntent = PendingIntent.getService(context, TriggerReceiver.class.getName().hashCode(), new Intent(context, TriggerReceiver.class), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pendingIntent = PendingIntent.getService(context, TriggerReceiver.class.getName().hashCode(), new Intent(context, TriggerReceiver.class), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); alarmManager.set(AlarmManager.RTC, Math.max(LastCheckinInfo.read(context).getLastCheckin() + REGULAR_CHECKIN_INTERVAL, System.currentTimeMillis() + BACKUP_CHECKIN_DELAY), pendingIntent); } } From 99177daf0fc8dcde2c3f788d9f6203ebd3a623e4 Mon Sep 17 00:00:00 2001 From: cuynu Date: Thu, 26 Sep 2024 23:21:02 +0700 Subject: [PATCH 10/29] test compile with targetSdk 33 --- build.gradle | 2 +- .../src/main/AndroidManifest.xml | 43 ++++++++++++++----- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index 60699d2e..e4c80045 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ buildscript { ext.androidBuildVersionTools = '33.0.2' ext.androidMinSdk = 23 - ext.androidTargetSdk = 30 + ext.androidTargetSdk = 33 ext.androidCompileSdk = 33 repositories { diff --git a/play-services-core/src/main/AndroidManifest.xml b/play-services-core/src/main/AndroidManifest.xml index 7cf8a16f..dddc5dc6 100644 --- a/play-services-core/src/main/AndroidManifest.xml +++ b/play-services-core/src/main/AndroidManifest.xml @@ -25,14 +25,17 @@ android:name="${basePackageName}.android.c2dm.permission.RECEIVE" android:label="@string/perm_c2dm_receive_label" android:permissionGroup="android.permission-group.NETWORK" + tools:node="remove" android:protectionLevel="normal" /> @@ -53,7 +56,7 @@ - + @@ -62,7 +65,8 @@ - + @@ -116,13 +120,15 @@ - + - + @@ -150,6 +156,7 @@ @@ -161,6 +168,7 @@ @@ -173,6 +181,7 @@ @@ -185,6 +194,7 @@ @@ -208,6 +218,7 @@ @@ -220,7 +231,8 @@ - + @@ -278,6 +290,7 @@ @@ -285,19 +298,22 @@ - + - + - + @@ -306,6 +322,7 @@ @@ -409,14 +428,16 @@ - + - + From 31955e783e6578f682c966b03a7f1659332cfe97 Mon Sep 17 00:00:00 2001 From: cuynu Date: Thu, 26 Sep 2024 23:54:18 +0700 Subject: [PATCH 11/29] bump gradle 8.0.2 --- build.gradle | 2 +- play-services-core/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index e4c80045..62b78afa 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ buildscript { ext.wireVersion = '4.8.0' - ext.androidBuildGradleVersion = '8.0.0' + ext.androidBuildGradleVersion = '8.0.2' ext.androidBuildVersionTools = '33.0.2' ext.androidMinSdk = 23 diff --git a/play-services-core/build.gradle b/play-services-core/build.gradle index a9d2351a..22e0b42c 100644 --- a/play-services-core/build.gradle +++ b/play-services-core/build.gradle @@ -57,7 +57,7 @@ android { defaultConfig { versionName version versionCode appVersionCode - resConfigs 'xxhdpi' + resourceConfigurations += ['xxhdpi'] minSdkVersion androidMinSdk targetSdkVersion androidTargetSdk From 34a0e32b2ad181bb33c80a2173ee5f66e83e0201 Mon Sep 17 00:00:00 2001 From: cuynu Date: Thu, 26 Sep 2024 23:55:42 +0700 Subject: [PATCH 12/29] bump gms 24.38.32 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 62b78afa..6462d4ab 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ buildscript { } -def gmsVersion = "24.28.34" +def gmsVersion = "24.38.32" def gmsVersionCode = Integer.parseInt(gmsVersion.replaceAll('\\.', '')) def ourVersionBase = "0.3.0" From 7a5ae620b23c2df5919710f5e8b2724572181615 Mon Sep 17 00:00:00 2001 From: cuynu Date: Thu, 26 Sep 2024 23:56:16 +0700 Subject: [PATCH 13/29] switch to monthly for now --- play-services-core/src/main/res/xml/preferences_google_more.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/play-services-core/src/main/res/xml/preferences_google_more.xml b/play-services-core/src/main/res/xml/preferences_google_more.xml index c018f3a7..a419362a 100755 --- a/play-services-core/src/main/res/xml/preferences_google_more.xml +++ b/play-services-core/src/main/res/xml/preferences_google_more.xml @@ -86,7 +86,7 @@ android:selectable="true" android:icon="@drawable/ic_info_outline" android:title="@string/build_date" - android:summary="DD MM YYYY - nightly"> + android:summary="DD MM YYYY - monthly"> From b3e0e54545462b028212fea72a903ca30cab3be5 Mon Sep 17 00:00:00 2001 From: cuynu Date: Fri, 27 Sep 2024 00:00:54 +0700 Subject: [PATCH 14/29] move serial preference to other category --- .../main/res/xml/preferences_device_registration.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/play-services-core/src/main/res/xml/preferences_device_registration.xml b/play-services-core/src/main/res/xml/preferences_device_registration.xml index 91c35133..4935bfb8 100755 --- a/play-services-core/src/main/res/xml/preferences_device_registration.xml +++ b/play-services-core/src/main/res/xml/preferences_device_registration.xml @@ -18,11 +18,6 @@ android:key="pref_device_profile_import" android:summary="@string/import_profile_summary" android:title="@string/import_profile_name" /> - + Date: Wed, 2 Oct 2024 16:18:37 +0700 Subject: [PATCH 15/29] Add preference for play licensing `microg@4ef2248` --- .../microg/gms/settings/SettingsContract.kt | 11 +++++ .../microg/gms/settings/SettingsProvider.kt | 21 ++++++++++ .../org/microg/gms/play/PlayPreferences.kt | 18 ++++++++ .../kotlin/org/microg/gms/ui/PlayFragment.kt | 42 +++++++++++++++++++ .../org/microg/gms/ui/SettingsFragment.kt | 15 +++++-- .../src/main/res/drawable/ic_play.xml | 10 +++++ .../src/main/res/navigation/nav_settings.xml | 10 +++++ .../src/main/res/values-ar/strings.xml | 5 +++ .../src/main/res/values-az/strings.xml | 5 +++ .../src/main/res/values-be/strings.xml | 5 +++ .../src/main/res/values-bn/strings.xml | 5 +++ .../src/main/res/values-cs/strings.xml | 5 +++ .../src/main/res/values-es-rES/strings.xml | 5 +++ .../src/main/res/values-fr/strings.xml | 5 +++ .../src/main/res/values-he/strings.xml | 5 +++ .../src/main/res/values-hi/strings.xml | 5 +++ .../src/main/res/values-id/strings.xml | 5 +++ .../src/main/res/values-it/strings.xml | 5 +++ .../src/main/res/values-ja/strings.xml | 5 +++ .../src/main/res/values-ko/strings.xml | 5 +++ .../src/main/res/values-lt/strings.xml | 5 +++ .../src/main/res/values-pt-rBR/strings.xml | 5 +++ .../src/main/res/values-ru/strings.xml | 5 +++ .../src/main/res/values-th/strings.xml | 5 +++ .../src/main/res/values-tr/strings.xml | 5 +++ .../src/main/res/values-uk/strings.xml | 5 +++ .../src/main/res/values-vi/strings.xml | 5 +++ .../src/main/res/values-zh-rCN/strings.xml | 5 +++ .../src/main/res/values-zh-rTW/strings.xml | 5 +++ .../src/main/res/values/strings.xml | 7 +++- .../main/res/xml/preferences_google_more.xml | 2 +- .../src/main/res/xml/preferences_play.xml | 12 ++++++ .../src/main/res/xml/preferences_start.xml | 5 +++ 33 files changed, 257 insertions(+), 6 deletions(-) create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/play/PlayPreferences.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/PlayFragment.kt create mode 100644 play-services-core/src/main/res/drawable/ic_play.xml create mode 100644 play-services-core/src/main/res/xml/preferences_play.xml diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt index 11d52bf9..eddfafe9 100644 --- a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt +++ b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt @@ -104,6 +104,17 @@ object SettingsContract { ) } + object Play { + private const val id = "play" + fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id) + fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id" + const val LICENSING = "play_licensing" + val PROJECTION = arrayOf( + LICENSING + ) + } + + private fun withoutCallingIdentity(f: () -> T): T { val identity = Binder.clearCallingIdentity() try { diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt index 39dc00e1..15b797e3 100644 --- a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt +++ b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt @@ -14,6 +14,7 @@ import android.content.SharedPreferences import android.database.Cursor import android.database.MatrixCursor import android.net.Uri +import org.microg.gms.settings.SettingsContract.Play import android.preference.PreferenceManager import org.microg.gms.common.PackageUtils.warnIfNotMainProcess import org.microg.gms.settings.SettingsContract.Auth @@ -68,6 +69,7 @@ class SettingsProvider : ContentProvider() { Gcm.getContentUri(context!!) -> queryGcm(projection ?: Gcm.PROJECTION) Auth.getContentUri(context!!) -> queryAuth(projection ?: Auth.PROJECTION) Profile.getContentUri(context!!) -> queryProfile(projection ?: Profile.PROJECTION) + Play.getContentUri(context!!) -> queryPlay(projection ?: Play.PROJECTION) else -> null } @@ -84,11 +86,30 @@ class SettingsProvider : ContentProvider() { Gcm.getContentUri(context!!) -> updateGcm(values) Auth.getContentUri(context!!) -> updateAuth(values) Profile.getContentUri(context!!) -> updateProfile(values) + Play.getContentUri(context!!) -> updatePlay(values) else -> return 0 } return 1 } + private fun queryPlay(p: Array): Cursor = MatrixCursor(p).addRow(p) { key -> + when (key) { + Play.LICENSING -> getSettingsBoolean(key, false) + else -> throw IllegalArgumentException("Unknown key: $key") + } + } + private fun updatePlay(values: ContentValues) { + if (values.size() == 0) return + val editor = preferences.edit() + values.valueSet().forEach { (key, value) -> + when (key) { + Play.LICENSING -> editor.putBoolean(key, value as Boolean) + else -> throw IllegalArgumentException("Unknown key: $key") + } + } + editor.apply() + } + private fun queryCheckIn(p: Array): Cursor = MatrixCursor(p).addRow(p) { key -> when (key) { CheckIn.ENABLED -> getSettingsBoolean(key, true) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/play/PlayPreferences.kt b/play-services-core/src/main/kotlin/org/microg/gms/play/PlayPreferences.kt new file mode 100644 index 00000000..fa906104 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/play/PlayPreferences.kt @@ -0,0 +1,18 @@ +package org.microg.gms.play +import android.content.Context +import org.microg.gms.settings.SettingsContract +object PlayPreferences { + @JvmStatic + fun isLicensingEnabled(context: Context): Boolean { + val projection = arrayOf(SettingsContract.Play.LICENSING) + return SettingsContract.getSettings(context, SettingsContract.Play.getContentUri(context), projection) { c -> + c.getInt(0) != 0 + } + } + @JvmStatic + fun setLicensingEnabled(context: Context, enabled: Boolean) { + SettingsContract.setSettings(context, SettingsContract.Play.getContentUri(context)) { + put(SettingsContract.Play.LICENSING, enabled) + } + } +} \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PlayFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PlayFragment.kt new file mode 100644 index 00000000..eb7f1515 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/PlayFragment.kt @@ -0,0 +1,42 @@ +package org.microg.gms.ui +import android.annotation.SuppressLint +import android.os.Bundle +import androidx.lifecycle.lifecycleScope +import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.TwoStatePreference +import com.mgoogle.android.gms.R +import org.microg.gms.play.PlayPreferences +class PlayFragment : PreferenceFragmentCompat() { + private lateinit var licensingEnabled: TwoStatePreference + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.preferences_play) + } + @SuppressLint("RestrictedApi") + override fun onBindPreferences() { + licensingEnabled = preferenceScreen.findPreference(PREF_LICENSING_ENABLED) ?: licensingEnabled + licensingEnabled.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + val appContext = requireContext().applicationContext + lifecycleScope.launchWhenResumed { + if (newValue is Boolean) { + PlayPreferences.setLicensingEnabled(appContext, newValue) + } + updateContent() + } + true + } + } + override fun onResume() { + super.onResume() + updateContent() + } + private fun updateContent() { + val appContext = requireContext().applicationContext + lifecycleScope.launchWhenResumed { + licensingEnabled.isChecked = PlayPreferences.isLicensingEnabled(appContext) + } + } + companion object { + const val PREF_LICENSING_ENABLED = "play_licensing" + } +} \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt index 86dd492d..e8cf7051 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt @@ -22,6 +22,7 @@ import org.microg.gms.settings.SettingsContract import org.microg.gms.ui.settings.SettingsProvider import org.microg.gms.ui.settings.getAllSettingsProviders import org.microg.tools.ui.ResourceSettingsFragment +import org.microg.gms.play.PlayPreferences import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController @@ -39,11 +40,17 @@ class SettingsFragment : ResourceSettingsFragment() { findNavController().navigate(requireContext(), R.id.openGcmSettings) true } - findPreference(PREF_ABOUT)?.setOnPreferenceClickListener { - findNavController().navigate(requireContext(), R.id.openAbout) + findPreference(PREF_PLAY)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + findNavController().navigate(requireContext(), R.id.openPlaySettings) true } - findPreference(PREF_ABOUT)?.summary = getString(R.string.about_version_str, AboutFragment.getSelfVersion(context)) + findPreference(PREF_ABOUT)!!.apply { + onPreferenceClickListener = Preference.OnPreferenceClickListener { + findNavController().navigate(requireContext(), R.id.openAbout) + true + } + summary = getString(org.microg.tools.ui.R.string.about_version_str, AboutFragment.getSelfVersion(context)) + } findPreference(SettingsContract.CheckIn.HIDE_LAUNCHER_ICON)?.apply { setOnPreferenceChangeListener { _, newValue -> @@ -106,6 +113,7 @@ class SettingsFragment : ResourceSettingsFragment() { } findPreference(PREF_CHECKIN)?.setSummary(if (CheckinPrefs.isEnabled(context)) R.string.service_status_enabled_short else R.string.service_status_disabled_short) + findPreference(PREF_PLAY)!!.setSummary(if (PlayPreferences.isLicensingEnabled(requireContext())) R.string.pref_play_summary_licensing_on else R.string.pref_play_summary_licensing_off) lifecycleScope.launchWhenResumed { val entries = getAllSettingsProviders(requireContext()).flatMap { it.getEntriesDynamic(requireContext()) } @@ -124,6 +132,7 @@ class SettingsFragment : ResourceSettingsFragment() { const val PREF_ABOUT = "pref_about" const val PREF_GCM = "pref_gcm" const val PREF_CHECKIN = "pref_checkin" + const val PREF_PLAY = "pref_play" } init { diff --git a/play-services-core/src/main/res/drawable/ic_play.xml b/play-services-core/src/main/res/drawable/ic_play.xml new file mode 100644 index 00000000..9d8129f3 --- /dev/null +++ b/play-services-core/src/main/res/drawable/ic_play.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/play-services-core/src/main/res/navigation/nav_settings.xml b/play-services-core/src/main/res/navigation/nav_settings.xml index fb1cfa00..fd1a42ff 100755 --- a/play-services-core/src/main/res/navigation/nav_settings.xml +++ b/play-services-core/src/main/res/navigation/nav_settings.xml @@ -11,6 +11,9 @@ + + + diff --git a/play-services-core/src/main/res/values-ar/strings.xml b/play-services-core/src/main/res/values-ar/strings.xml index 5d4cd8ea..0043af17 100644 --- a/play-services-core/src/main/res/values-ar/strings.xml +++ b/play-services-core/src/main/res/values-ar/strings.xml @@ -138,4 +138,9 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-az/strings.xml b/play-services-core/src/main/res/values-az/strings.xml index 740a9b11..500e7ea7 100644 --- a/play-services-core/src/main/res/values-az/strings.xml +++ b/play-services-core/src/main/res/values-az/strings.xml @@ -138,4 +138,9 @@ Bu bir neçə dəqiqə çəkə bilər." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-be/strings.xml b/play-services-core/src/main/res/values-be/strings.xml index 1152301e..339f72ea 100644 --- a/play-services-core/src/main/res/values-be/strings.xml +++ b/play-services-core/src/main/res/values-be/strings.xml @@ -138,4 +138,9 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-bn/strings.xml b/play-services-core/src/main/res/values-bn/strings.xml index 0156013d..2c33052f 100644 --- a/play-services-core/src/main/res/values-bn/strings.xml +++ b/play-services-core/src/main/res/values-bn/strings.xml @@ -139,4 +139,9 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-cs/strings.xml b/play-services-core/src/main/res/values-cs/strings.xml index 7e021dd8..df04f144 100644 --- a/play-services-core/src/main/res/values-cs/strings.xml +++ b/play-services-core/src/main/res/values-cs/strings.xml @@ -135,4 +135,9 @@ Tato akce může trvat několik minut." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-es-rES/strings.xml b/play-services-core/src/main/res/values-es-rES/strings.xml index 5b090832..ef2e4b05 100644 --- a/play-services-core/src/main/res/values-es-rES/strings.xml +++ b/play-services-core/src/main/res/values-es-rES/strings.xml @@ -138,4 +138,9 @@ Esto puede tardar unos minutos." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-fr/strings.xml b/play-services-core/src/main/res/values-fr/strings.xml index 0fcac240..1fdd82f3 100644 --- a/play-services-core/src/main/res/values-fr/strings.xml +++ b/play-services-core/src/main/res/values-fr/strings.xml @@ -138,4 +138,9 @@ Cela peut prendre quelques minutes." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-he/strings.xml b/play-services-core/src/main/res/values-he/strings.xml index 95511eb1..ecd90758 100644 --- a/play-services-core/src/main/res/values-he/strings.xml +++ b/play-services-core/src/main/res/values-he/strings.xml @@ -85,4 +85,9 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-hi/strings.xml b/play-services-core/src/main/res/values-hi/strings.xml index fdf8ea5a..cad50b4c 100644 --- a/play-services-core/src/main/res/values-hi/strings.xml +++ b/play-services-core/src/main/res/values-hi/strings.xml @@ -137,4 +137,9 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-id/strings.xml b/play-services-core/src/main/res/values-id/strings.xml index ac8b9869..e00d9da4 100644 --- a/play-services-core/src/main/res/values-id/strings.xml +++ b/play-services-core/src/main/res/values-id/strings.xml @@ -136,4 +136,9 @@ Ini bisa berlangsung beberapa menit." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-it/strings.xml b/play-services-core/src/main/res/values-it/strings.xml index 07277b42..e73bffc2 100755 --- a/play-services-core/src/main/res/values-it/strings.xml +++ b/play-services-core/src/main/res/values-it/strings.xml @@ -135,4 +135,9 @@ Questo potrà richiedere un paio di minuti" Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-ja/strings.xml b/play-services-core/src/main/res/values-ja/strings.xml index 0d93256f..86fad15d 100644 --- a/play-services-core/src/main/res/values-ja/strings.xml +++ b/play-services-core/src/main/res/values-ja/strings.xml @@ -138,4 +138,9 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-ko/strings.xml b/play-services-core/src/main/res/values-ko/strings.xml index fa18f6d5..13b7a04f 100644 --- a/play-services-core/src/main/res/values-ko/strings.xml +++ b/play-services-core/src/main/res/values-ko/strings.xml @@ -138,4 +138,9 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-lt/strings.xml b/play-services-core/src/main/res/values-lt/strings.xml index bdf153d4..ce13b1f3 100644 --- a/play-services-core/src/main/res/values-lt/strings.xml +++ b/play-services-core/src/main/res/values-lt/strings.xml @@ -138,4 +138,9 @@ Tai gali užtrukti keletą minučių." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-pt-rBR/strings.xml b/play-services-core/src/main/res/values-pt-rBR/strings.xml index 1120864e..a819d634 100644 --- a/play-services-core/src/main/res/values-pt-rBR/strings.xml +++ b/play-services-core/src/main/res/values-pt-rBR/strings.xml @@ -156,4 +156,9 @@ Isso pode demorar alguns minutos." Gerenciar contas do Google conectadas Isso abrirá as configurações do seu dispositivo ! Configurações diversas + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-ru/strings.xml b/play-services-core/src/main/res/values-ru/strings.xml index 61269e80..00c399e6 100644 --- a/play-services-core/src/main/res/values-ru/strings.xml +++ b/play-services-core/src/main/res/values-ru/strings.xml @@ -138,4 +138,9 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-th/strings.xml b/play-services-core/src/main/res/values-th/strings.xml index 3f2df561..2f613b19 100644 --- a/play-services-core/src/main/res/values-th/strings.xml +++ b/play-services-core/src/main/res/values-th/strings.xml @@ -126,4 +126,9 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-tr/strings.xml b/play-services-core/src/main/res/values-tr/strings.xml index d5f5ddf5..24f96a11 100644 --- a/play-services-core/src/main/res/values-tr/strings.xml +++ b/play-services-core/src/main/res/values-tr/strings.xml @@ -138,4 +138,9 @@ Bunu bilerek yaptıysanız, Google'ın oturum açma sayfasına bağlanmak için Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-uk/strings.xml b/play-services-core/src/main/res/values-uk/strings.xml index a63b5a67..98e3dad5 100644 --- a/play-services-core/src/main/res/values-uk/strings.xml +++ b/play-services-core/src/main/res/values-uk/strings.xml @@ -138,4 +138,9 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-vi/strings.xml b/play-services-core/src/main/res/values-vi/strings.xml index df22a69d..33409f1d 100644 --- a/play-services-core/src/main/res/values-vi/strings.xml +++ b/play-services-core/src/main/res/values-vi/strings.xml @@ -141,4 +141,9 @@ Hãy thử lại sau." Quản lý tài khoản Google đã đăng nhập Điều này sẽ mở cài đặt thiết bị của bạn ! Cài đặt khác + Tự động cấp phép đang tắt + Tự động cấp phép đang bật + Tự động cấp phép + Một số ứng dụng có thể yêu cầu xác minh rằng bạn đã mua từ Google Play hay không. Khi ứng dụng đó yêu cầu, Vanced+ microG có thể chứng minh là bạn đã mua ứng dụng đó từ Google Play. Điều này sẽ không áp dụng nếu tùy chọn này được tắt hoặc không có tài khoản Google nào được thêm vào. + Dịch vụ Play diff --git a/play-services-core/src/main/res/values-zh-rCN/strings.xml b/play-services-core/src/main/res/values-zh-rCN/strings.xml index 5dc520b8..31bb1f24 100644 --- a/play-services-core/src/main/res/values-zh-rCN/strings.xml +++ b/play-services-core/src/main/res/values-zh-rCN/strings.xml @@ -137,4 +137,9 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values-zh-rTW/strings.xml b/play-services-core/src/main/res/values-zh-rTW/strings.xml index f4105881..9c80ed44 100644 --- a/play-services-core/src/main/res/values-zh-rTW/strings.xml +++ b/play-services-core/src/main/res/values-zh-rTW/strings.xml @@ -145,4 +145,9 @@ Vanced+ microG 會把 Google 帳戶名稱以外的識別位 Manage signed in Google accounts This will open your device settings ! Miscellaneous settings + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Play Store services diff --git a/play-services-core/src/main/res/values/strings.xml b/play-services-core/src/main/res/values/strings.xml index 236f1198..c4cd7a0a 100755 --- a/play-services-core/src/main/res/values/strings.xml +++ b/play-services-core/src/main/res/values/strings.xml @@ -119,7 +119,10 @@ This can take a couple of minutes." Messages: %1$d (%2$d bytes) Disconnected Connected since %1$s - + Licensing off + Licensing on + Answer license verification requests + Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. Allow registration Allow the app to register for push notifications. Start app on push message @@ -129,7 +132,7 @@ This can take a couple of minutes." Registered apps Unregistered apps Networks to use for push notifications - + Play Store services Device profile Select profile Native diff --git a/play-services-core/src/main/res/xml/preferences_google_more.xml b/play-services-core/src/main/res/xml/preferences_google_more.xml index a419362a..1c777be2 100755 --- a/play-services-core/src/main/res/xml/preferences_google_more.xml +++ b/play-services-core/src/main/res/xml/preferences_google_more.xml @@ -86,7 +86,7 @@ android:selectable="true" android:icon="@drawable/ic_info_outline" android:title="@string/build_date" - android:summary="DD MM YYYY - monthly"> + android:summary="27 September 2024 - monthly"> diff --git a/play-services-core/src/main/res/xml/preferences_play.xml b/play-services-core/src/main/res/xml/preferences_play.xml new file mode 100644 index 00000000..df28b60a --- /dev/null +++ b/play-services-core/src/main/res/xml/preferences_play.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/play-services-core/src/main/res/xml/preferences_start.xml b/play-services-core/src/main/res/xml/preferences_start.xml index e7372cee..ae135d57 100755 --- a/play-services-core/src/main/res/xml/preferences_start.xml +++ b/play-services-core/src/main/res/xml/preferences_start.xml @@ -38,6 +38,11 @@ android:title="@string/hideLauncherIcon" android:icon="@drawable/ic_baseline_hide_source_24" android:defaultValue="true"/> + + Date: Wed, 2 Oct 2024 16:23:18 +0700 Subject: [PATCH 16/29] Expose settings via signature level permission "microg@05ca063" --- play-services-base-core/src/main/AndroidManifest.xml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/play-services-base-core/src/main/AndroidManifest.xml b/play-services-base-core/src/main/AndroidManifest.xml index 5c321135..013e3b18 100644 --- a/play-services-base-core/src/main/AndroidManifest.xml +++ b/play-services-base-core/src/main/AndroidManifest.xml @@ -6,11 +6,18 @@ + + + + android:exported="true" + android:readPermission="org.microg.gms.permission.READ_SETTINGS" + android:writePermission="org.microg.gms.permission.WRITE_SETTINGS" /> Date: Wed, 2 Oct 2024 16:25:30 +0700 Subject: [PATCH 17/29] No hardcoded application name in setting permission names "microg@53c683a" --- play-services-base-core/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/play-services-base-core/src/main/AndroidManifest.xml b/play-services-base-core/src/main/AndroidManifest.xml index 013e3b18..084e5119 100644 --- a/play-services-base-core/src/main/AndroidManifest.xml +++ b/play-services-base-core/src/main/AndroidManifest.xml @@ -6,9 +6,9 @@ - - From 82e7c9fd46f2a578249e54799996730b9a4741ed Mon Sep 17 00:00:00 2001 From: cuynu Date: Wed, 2 Oct 2024 16:26:10 +0700 Subject: [PATCH 18/29] No hardcoded application name in setting permission uses "microg@2b186fd" --- play-services-base-core/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/play-services-base-core/src/main/AndroidManifest.xml b/play-services-base-core/src/main/AndroidManifest.xml index 084e5119..369707e7 100644 --- a/play-services-base-core/src/main/AndroidManifest.xml +++ b/play-services-base-core/src/main/AndroidManifest.xml @@ -16,8 +16,8 @@ android:name="org.microg.gms.settings.SettingsProvider" android:authorities="${applicationId}.microg.settings" android:exported="true" - android:readPermission="org.microg.gms.permission.READ_SETTINGS" - android:writePermission="org.microg.gms.permission.WRITE_SETTINGS" /> + android:readPermission="${applicationId}.permission.READ_SETTINGS" + android:writePermission="${applicationId}.permission.WRITE_SETTINGS" /> Date: Wed, 2 Oct 2024 16:29:52 +0700 Subject: [PATCH 19/29] microG settings must be exported --- play-services-core/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/play-services-core/src/main/AndroidManifest.xml b/play-services-core/src/main/AndroidManifest.xml index dddc5dc6..2a35d999 100644 --- a/play-services-core/src/main/AndroidManifest.xml +++ b/play-services-core/src/main/AndroidManifest.xml @@ -105,7 +105,7 @@ + android:exported="true" /> From 3f7d3cb596a21a3a05efa36e2426c8c225d95312 Mon Sep 17 00:00:00 2001 From: cuynu Date: Wed, 2 Oct 2024 17:12:35 +0700 Subject: [PATCH 20/29] Themes + Material3 improvements "microg@b62f089" "microg@4fc5b75" --- .../tools/ui/AbstractSettingsActivity.java | 3 ++- .../src/main/res/layout/settings_activity.xml | 8 ++++++ .../src/main/AndroidManifest.xml | 10 ++++---- ...ctivity.java => MainSettingsActivity.java} | 25 +++++++++++++------ .../preferences_material_switch_color.xml | 5 ++++ .../res/layout/preference_material_switch.xml | 11 ++++++++ .../main/res/layout/preference_switch_bar.xml | 6 ++--- .../res/layout/settings_root_activity.xml | 7 ++++++ .../src/main/res/values-night-v23/themes.xml | 8 ++++++ .../src/main/res/values-night-v27/themes.xml | 9 +++++++ .../src/main/res/values-night-v31/themes.xml | 21 +++++++--------- .../src/main/res/values-v23/themes.xml | 8 ++++++ .../src/main/res/values-v27/themes.xml | 9 +++++++ .../src/main/res/values-v31/themes.xml | 20 +++++++-------- .../src/main/res/values/themes.xml | 17 +++++++++++++ .../main/res/xml/preferences_google_more.xml | 2 +- 16 files changed, 128 insertions(+), 41 deletions(-) rename play-services-core/src/main/java/org/microg/gms/ui/{SettingsActivity.java => MainSettingsActivity.java} (66%) mode change 100755 => 100644 create mode 100644 play-services-core/src/main/res/color/preferences_material_switch_color.xml create mode 100644 play-services-core/src/main/res/layout/preference_material_switch.xml create mode 100644 play-services-core/src/main/res/values-night-v23/themes.xml create mode 100644 play-services-core/src/main/res/values-night-v27/themes.xml create mode 100644 play-services-core/src/main/res/values-v23/themes.xml create mode 100644 play-services-core/src/main/res/values-v27/themes.xml diff --git a/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/AbstractSettingsActivity.java b/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/AbstractSettingsActivity.java index a771a9ea..2b0542a5 100644 --- a/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/AbstractSettingsActivity.java +++ b/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/AbstractSettingsActivity.java @@ -3,7 +3,7 @@ package org.microg.tools.ui; import android.os.Bundle; import android.view.MenuItem; import android.view.ViewGroup; - +import androidx.appcompat.widget.Toolbar; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; @@ -19,6 +19,7 @@ public abstract class AbstractSettingsActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.settings_activity); + setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); if (showHomeAsUp) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); } diff --git a/play-services-core/microg-ui-tools/src/main/res/layout/settings_activity.xml b/play-services-core/microg-ui-tools/src/main/res/layout/settings_activity.xml index a664de26..e5f71828 100644 --- a/play-services-core/microg-ui-tools/src/main/res/layout/settings_activity.xml +++ b/play-services-core/microg-ui-tools/src/main/res/layout/settings_activity.xml @@ -19,6 +19,14 @@ android:layout_height="match_parent" android:orientation="vertical"> + + + @@ -321,7 +321,7 @@ @@ -357,7 +357,7 @@ android:icon="@mipmap/ic_launcher" android:label="@string/gms_settings_name" android:process=":ui" - android:targetActivity="org.microg.gms.ui.SettingsActivity" + android:targetActivity="org.microg.gms.ui.MainSettingsActivity" android:taskAffinity="org.microg.gms.settings" android:theme="@style/AppTheme"> @@ -380,7 +380,7 @@ android:name="com.google.android.gms.app.settings.GoogleSettingsLink" android:process=":ui" android:exported="true" - android:targetActivity="org.microg.gms.ui.SettingsActivity" + android:targetActivity="org.microg.gms.ui.MainSettingsActivity" android:taskAffinity="org.microg.gms.settings"> diff --git a/play-services-core/src/main/java/org/microg/gms/ui/SettingsActivity.java b/play-services-core/src/main/java/org/microg/gms/ui/MainSettingsActivity.java old mode 100755 new mode 100644 similarity index 66% rename from play-services-core/src/main/java/org/microg/gms/ui/SettingsActivity.java rename to play-services-core/src/main/java/org/microg/gms/ui/MainSettingsActivity.java index f0777081..b65b3806 --- a/play-services-core/src/main/java/org/microg/gms/ui/SettingsActivity.java +++ b/play-services-core/src/main/java/org/microg/gms/ui/MainSettingsActivity.java @@ -1,7 +1,6 @@ package org.microg.gms.ui; -import static android.os.Build.VERSION.SDK_INT; - +import android.content.Intent; import android.os.Bundle; import androidx.annotation.Nullable; @@ -11,10 +10,12 @@ import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.ui.AppBarConfiguration; import androidx.navigation.ui.NavigationUI; -import com.google.android.material.color.DynamicColors; import com.mgoogle.android.gms.R; +import org.microg.gms.ui.settings.SettingsProvider; -public class SettingsActivity extends AppCompatActivity { +import static org.microg.gms.ui.settings.SettingsProviderKt.getAllSettingsProviders; + +public class MainSettingsActivity extends AppCompatActivity { private AppBarConfiguration appBarConfiguration; private NavController getNavController() { @@ -24,10 +25,18 @@ public class SettingsActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.settings_root_activity); - if (SDK_INT >= 31) { - DynamicColors.applyToActivityIfAvailable(this); + + Intent intent = getIntent(); + for (SettingsProvider settingsProvider : getAllSettingsProviders(this)) { + settingsProvider.preProcessSettingsIntent(intent); } + + setContentView(R.layout.settings_root_activity); + + for (SettingsProvider settingsProvider : getAllSettingsProviders(this)) { + settingsProvider.extendNavigation(getNavController()); + } + appBarConfiguration = new AppBarConfiguration.Builder(getNavController().getGraph()).build(); NavigationUI.setupActionBarWithNavController(this, getNavController(), appBarConfiguration); } @@ -36,4 +45,4 @@ public class SettingsActivity extends AppCompatActivity { public boolean onSupportNavigateUp() { return NavigationUI.navigateUp(getNavController(), appBarConfiguration) || super.onSupportNavigateUp(); } -} +} \ No newline at end of file diff --git a/play-services-core/src/main/res/color/preferences_material_switch_color.xml b/play-services-core/src/main/res/color/preferences_material_switch_color.xml new file mode 100644 index 00000000..1a6c9037 --- /dev/null +++ b/play-services-core/src/main/res/color/preferences_material_switch_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/play-services-core/src/main/res/layout/preference_material_switch.xml b/play-services-core/src/main/res/layout/preference_material_switch.xml new file mode 100644 index 00000000..071caab2 --- /dev/null +++ b/play-services-core/src/main/res/layout/preference_material_switch.xml @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/play-services-core/src/main/res/layout/preference_switch_bar.xml b/play-services-core/src/main/res/layout/preference_switch_bar.xml index d45909cd..346b1dd4 100755 --- a/play-services-core/src/main/res/layout/preference_switch_bar.xml +++ b/play-services-core/src/main/res/layout/preference_switch_bar.xml @@ -52,9 +52,7 @@ android:maxLines="1" android:paddingStart="56dp" android:paddingLeft="56dp" - android:text="@{description}" - android:textSize="20sp" - android:textAppearance="@style/TextAppearance.M3.Sys.Typescale.HeadlineSmall" + android:textColor="@android:color/white" tools:text="Enabled" /> + + + + + \ No newline at end of file diff --git a/play-services-core/src/main/res/values-night-v27/themes.xml b/play-services-core/src/main/res/values-night-v27/themes.xml new file mode 100644 index 00000000..0b22714a --- /dev/null +++ b/play-services-core/src/main/res/values-night-v27/themes.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/play-services-core/src/main/res/values-night-v31/themes.xml b/play-services-core/src/main/res/values-night-v31/themes.xml index de5386e8..7f89bd04 100644 --- a/play-services-core/src/main/res/values-night-v31/themes.xml +++ b/play-services-core/src/main/res/values-night-v31/themes.xml @@ -1,14 +1,11 @@ + - - + \ No newline at end of file diff --git a/play-services-core/src/main/res/values-v23/themes.xml b/play-services-core/src/main/res/values-v23/themes.xml new file mode 100644 index 00000000..9009e5c5 --- /dev/null +++ b/play-services-core/src/main/res/values-v23/themes.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/play-services-core/src/main/res/values-v27/themes.xml b/play-services-core/src/main/res/values-v27/themes.xml new file mode 100644 index 00000000..434c86ec --- /dev/null +++ b/play-services-core/src/main/res/values-v27/themes.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/play-services-core/src/main/res/values-v31/themes.xml b/play-services-core/src/main/res/values-v31/themes.xml index 1719a989..6e96e2b4 100644 --- a/play-services-core/src/main/res/values-v31/themes.xml +++ b/play-services-core/src/main/res/values-v31/themes.xml @@ -1,13 +1,11 @@ + - - + \ No newline at end of file diff --git a/play-services-core/src/main/res/values/themes.xml b/play-services-core/src/main/res/values/themes.xml index d5cb5705..8e651928 100755 --- a/play-services-core/src/main/res/values/themes.xml +++ b/play-services-core/src/main/res/values/themes.xml @@ -22,6 +22,15 @@ @color/m3_theme_primary_dark + + + + + + + + diff --git a/play-services-core/src/main/res/xml/preferences_google_more.xml b/play-services-core/src/main/res/xml/preferences_google_more.xml index 1c777be2..0d348123 100755 --- a/play-services-core/src/main/res/xml/preferences_google_more.xml +++ b/play-services-core/src/main/res/xml/preferences_google_more.xml @@ -68,7 +68,7 @@ android:key="auth_manager_visible" android:summary="@string/pref_auth_visible_summary" android:title="@string/pref_auth_visible_title"/> - Date: Wed, 2 Oct 2024 17:34:44 +0700 Subject: [PATCH 21/29] update play icon --- play-services-core/src/main/res/drawable/ic_play.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/play-services-core/src/main/res/drawable/ic_play.xml b/play-services-core/src/main/res/drawable/ic_play.xml index 9d8129f3..9db10ec6 100644 --- a/play-services-core/src/main/res/drawable/ic_play.xml +++ b/play-services-core/src/main/res/drawable/ic_play.xml @@ -3,8 +3,8 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="?attr/colorAccent"> + android:tint="?attr/colorPrimary"> \ No newline at end of file From b96a8d4727fd228c1b13ccd4aa3730a8a4e7ce35 Mon Sep 17 00:00:00 2001 From: cuynu Date: Wed, 2 Oct 2024 23:46:17 +0700 Subject: [PATCH 22/29] UI: Unify preferences "microg@d831bbc" --- build.gradle | 2 +- .../microg/gms/settings/SettingsContract.kt | 1 - .../res/layout/preference_app_heading.xml | 43 +++++ .../main/res/layout/preference_switch_bar.xml | 42 +++++ .../microg/gms/auth/login/LoginActivity.java | 6 +- .../microg/gms/checkin/CheckinManager.java | 4 +- .../microg/gms/checkin/CheckinService.java | 2 +- .../microg/gms/checkin/TriggerReceiver.java | 2 +- .../org/microg/gms/gcm/TriggerReceiver.java | 4 +- ...{CheckinPrefs.kt => CheckinPreferences.kt} | 26 ++- .../kotlin/org/microg/gms/gcm/GcmPrefs.kt | 11 +- .../org/microg/gms/gcm/PushRegisterService.kt | 4 +- .../org/microg/gms/ui/AppHeadingPreference.kt | 44 +++++ .../org/microg/gms/ui/AppIconPreference.kt | 3 +- .../kotlin/org/microg/gms/ui/AppPreference.kt | 47 +++++ .../gms/ui/DeviceRegistrationFragment.kt | 172 +++++++++++++++--- .../DeviceRegistrationPreferencesFragment.kt | 164 ----------------- .../gms/ui/PreferenceSwitchBarCallback.kt | 10 - .../gms/ui/PushNotificationAllAppsFragment.kt | 6 +- .../gms/ui/PushNotificationAppFragment.kt | 151 +++++++++++---- .../PushNotificationAppPreferencesFragment.kt | 137 -------------- .../microg/gms/ui/PushNotificationFragment.kt | 153 ++++++++++++---- .../ui/PushNotificationPreferencesFragment.kt | 128 ------------- .../org/microg/gms/ui/SettingsFragment.kt | 4 +- .../org/microg/gms/ui/SwitchBarPreference.kt | 51 ++++++ .../layout/device_registration_fragment.xml | 40 ---- .../res/layout/preference_app_heading.xml | 43 +++++ .../main/res/layout/preference_switch_bar.xml | 99 ++++------ .../layout/push_notification_app_fragment.xml | 81 --------- .../res/layout/push_notification_fragment.xml | 44 ----- .../xml/preferences_device_registration.xml | 9 +- .../xml/preferences_push_notifications.xml | 5 + .../preferences_push_notifications_app.xml | 5 + 33 files changed, 745 insertions(+), 798 deletions(-) create mode 100644 play-services-base-core/src/main/res/layout/preference_app_heading.xml create mode 100644 play-services-base-core/src/main/res/layout/preference_switch_bar.xml rename play-services-core/src/main/kotlin/org/microg/gms/checkin/{CheckinPrefs.kt => CheckinPreferences.kt} (60%) create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/AppHeadingPreference.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/AppPreference.kt delete mode 100755 play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt delete mode 100755 play-services-core/src/main/kotlin/org/microg/gms/ui/PreferenceSwitchBarCallback.kt delete mode 100755 play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppPreferencesFragment.kt delete mode 100755 play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationPreferencesFragment.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/SwitchBarPreference.kt delete mode 100755 play-services-core/src/main/res/layout/device_registration_fragment.xml create mode 100644 play-services-core/src/main/res/layout/preference_app_heading.xml delete mode 100755 play-services-core/src/main/res/layout/push_notification_app_fragment.xml delete mode 100755 play-services-core/src/main/res/layout/push_notification_fragment.xml diff --git a/build.gradle b/build.gradle index 6462d4ab..01047d0b 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ buildscript { ext.androidBuildVersionTools = '33.0.2' ext.androidMinSdk = 23 - ext.androidTargetSdk = 33 + ext.androidTargetSdk = 30 ext.androidCompileSdk = 33 repositories { diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt index eddfafe9..031b178d 100644 --- a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt +++ b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt @@ -22,7 +22,6 @@ object SettingsContract { const val SECURITY_TOKEN = "securityToken" const val VERSION_INFO = "versionInfo" const val DEVICE_DATA_VERSION_INFO = "deviceDataVersionInfo" - const val BRAND_SPOOF = "brandSpoof" const val HIDE_LAUNCHER_ICON = "hideLauncherIcon" diff --git a/play-services-base-core/src/main/res/layout/preference_app_heading.xml b/play-services-base-core/src/main/res/layout/preference_app_heading.xml new file mode 100644 index 00000000..cb7e4edf --- /dev/null +++ b/play-services-base-core/src/main/res/layout/preference_app_heading.xml @@ -0,0 +1,43 @@ + + + + + + + \ No newline at end of file diff --git a/play-services-base-core/src/main/res/layout/preference_switch_bar.xml b/play-services-base-core/src/main/res/layout/preference_switch_bar.xml new file mode 100644 index 00000000..9818305b --- /dev/null +++ b/play-services-base-core/src/main/res/layout/preference_switch_bar.xml @@ -0,0 +1,42 @@ + + + + + + + + \ No newline at end of file diff --git a/play-services-core/src/main/java/org/microg/gms/auth/login/LoginActivity.java b/play-services-core/src/main/java/org/microg/gms/auth/login/LoginActivity.java index 5d836001..f52b93c4 100644 --- a/play-services-core/src/main/java/org/microg/gms/auth/login/LoginActivity.java +++ b/play-services-core/src/main/java/org/microg/gms/auth/login/LoginActivity.java @@ -25,9 +25,9 @@ import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT; import static org.microg.gms.auth.AuthPrefs.isAuthVisible; -import static org.microg.gms.checkin.CheckinPrefs.hideLauncherIcon; -import static org.microg.gms.checkin.CheckinPrefs.isSpoofingEnabled; -import static org.microg.gms.checkin.CheckinPrefs.setSpoofingEnabled; +import static org.microg.gms.checkin.CheckinPreferences.hideLauncherIcon; +import static org.microg.gms.checkin.CheckinPreferences.isSpoofingEnabled; +import static org.microg.gms.checkin.CheckinPreferences.setSpoofingEnabled; import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME; import static org.microg.gms.common.Constants.GMS_VERSION_CODE; diff --git a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinManager.java b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinManager.java index dc67b444..b9432ac6 100755 --- a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinManager.java +++ b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinManager.java @@ -16,7 +16,7 @@ package org.microg.gms.checkin; -import static org.microg.gms.checkin.CheckinPrefs.isSpoofingEnabled; +import static org.microg.gms.checkin.CheckinPreferences.isSpoofingEnabled; import android.accounts.Account; import android.accounts.AccountManager; @@ -43,7 +43,7 @@ public class CheckinManager { LastCheckinInfo info = LastCheckinInfo.read(context); if (!force && info.getLastCheckin() > System.currentTimeMillis() - MIN_CHECKIN_INTERVAL) return null; - if (!CheckinPrefs.isEnabled(context)) + if (!CheckinPreferences.isEnabled(context)) return null; List accounts = new ArrayList<>(); AccountManager accountManager = AccountManager.get(context); diff --git a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinService.java b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinService.java index 8f00098f..3f53ebcd 100755 --- a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinService.java +++ b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinService.java @@ -80,7 +80,7 @@ public class CheckinService extends IntentService { protected void onHandleIntent(Intent intent) { try { ForegroundServiceContext.completeForegroundService(this, intent, TAG); - if (CheckinPrefs.isEnabled(this)) { + if (CheckinPreferences.isEnabled(this)) { LastCheckinInfo info = CheckinManager.checkin(this, intent.getBooleanExtra(EXTRA_FORCE_CHECKIN, false)); if (info != null) { Log.d(TAG, "Checked in as " + Long.toHexString(info.getAndroidId())); diff --git a/play-services-core/src/main/java/org/microg/gms/checkin/TriggerReceiver.java b/play-services-core/src/main/java/org/microg/gms/checkin/TriggerReceiver.java index 752b8119..e41a954b 100755 --- a/play-services-core/src/main/java/org/microg/gms/checkin/TriggerReceiver.java +++ b/play-services-core/src/main/java/org/microg/gms/checkin/TriggerReceiver.java @@ -41,7 +41,7 @@ public class TriggerReceiver extends WakefulBroadcastReceiver { try { boolean force = "android.provider.Telephony.SECRET_CODE".equals(intent.getAction()); - if (CheckinPrefs.isEnabled(context) || force) { + if (CheckinPreferences.isEnabled(context) || force) { if (LastCheckinInfo.read(context).getLastCheckin() > System.currentTimeMillis() - REGULAR_CHECKIN_INTERVAL && !force) { CheckinService.schedule(context); return; diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/TriggerReceiver.java b/play-services-core/src/main/java/org/microg/gms/gcm/TriggerReceiver.java index e94b2f02..83d182aa 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/TriggerReceiver.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/TriggerReceiver.java @@ -30,7 +30,7 @@ import android.util.Log; import androidx.legacy.content.WakefulBroadcastReceiver; -import org.microg.gms.checkin.CheckinPrefs; +import org.microg.gms.checkin.CheckinPreferences; import org.microg.gms.checkin.LastCheckinInfo; import org.microg.gms.common.ForegroundServiceContext; @@ -67,7 +67,7 @@ public class TriggerReceiver extends WakefulBroadcastReceiver { if (LastCheckinInfo.read(context).getAndroidId() == 0) { Log.d(TAG, "Ignoring " + intent + ": need to checkin first."); - if (CheckinPrefs.isEnabled(context)) { + if (CheckinPreferences.isEnabled(context)) { // Do a check-in if we are not actually checked in, // but should be, e.g. cleared app data Log.d(TAG, "Requesting check-in..."); diff --git a/play-services-core/src/main/kotlin/org/microg/gms/checkin/CheckinPrefs.kt b/play-services-core/src/main/kotlin/org/microg/gms/checkin/CheckinPreferences.kt similarity index 60% rename from play-services-core/src/main/kotlin/org/microg/gms/checkin/CheckinPrefs.kt rename to play-services-core/src/main/kotlin/org/microg/gms/checkin/CheckinPreferences.kt index e2ab990a..eb78d498 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/checkin/CheckinPrefs.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/checkin/CheckinPreferences.kt @@ -5,16 +5,21 @@ package org.microg.gms.checkin import android.content.Context +import android.content.Intent import org.microg.gms.settings.SettingsContract import org.microg.gms.settings.SettingsContract.CheckIn import org.microg.gms.settings.SettingsContract.setSettings -object CheckinPrefs { +object CheckinPreferences { @JvmStatic fun isEnabled(context: Context): Boolean { val projection = arrayOf(CheckIn.ENABLED) - return SettingsContract.getSettings(context, CheckIn.getContentUri(context), projection) { c -> + return SettingsContract.getSettings( + context, + CheckIn.getContentUri(context), + projection + ) { c -> c.getInt(0) != 0 } } @@ -22,7 +27,11 @@ object CheckinPrefs { @JvmStatic fun isSpoofingEnabled(context: Context): Boolean { val projection = arrayOf(CheckIn.BRAND_SPOOF) - return SettingsContract.getSettings(context, CheckIn.getContentUri(context), projection) { c -> + return SettingsContract.getSettings( + context, + CheckIn.getContentUri(context), + projection + ) { c -> c.getInt(0) != 0 } } @@ -41,4 +50,13 @@ object CheckinPrefs { } } -} + @JvmStatic + fun setEnabled(context: Context, enabled: Boolean) { + SettingsContract.setSettings(context, CheckIn.getContentUri(context)) { + put(CheckIn.ENABLED, enabled) + } + if (enabled) { + context.sendOrderedBroadcast(Intent(context, TriggerReceiver::class.java), null) + } + } +} \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/gcm/GcmPrefs.kt b/play-services-core/src/main/kotlin/org/microg/gms/gcm/GcmPrefs.kt index 86e7a37d..c506ed62 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/gcm/GcmPrefs.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/gcm/GcmPrefs.kt @@ -71,6 +71,15 @@ data class GcmPrefs( gcmPrefs.setEnabled(context, config.enabled) } + fun setEnabled(context: Context, enabled: Boolean) { + val prefs = get(context) + setSettings(context, Gcm.getContentUri(context)) { + put(Gcm.ENABLE_GCM, enabled) + } + prefs.setEnabled(context, enabled) + } + + @JvmStatic fun clearLastPersistedId(context: Context) { setSettings(context, Gcm.getContentUri(context)) { @@ -79,6 +88,7 @@ data class GcmPrefs( } } + /** * Call this whenever the enabled state of GCM has changed. */ @@ -178,5 +188,4 @@ data class GcmPrefs( put(Gcm.LAST_PERSISTENT_ID, newId) } } - } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/gcm/PushRegisterService.kt b/play-services-core/src/main/kotlin/org/microg/gms/gcm/PushRegisterService.kt index 1f27e4b6..8d3b9a78 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/gcm/PushRegisterService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/gcm/PushRegisterService.kt @@ -16,7 +16,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleService import androidx.lifecycle.lifecycleScope -import org.microg.gms.checkin.CheckinPrefs +import org.microg.gms.checkin.CheckinPreferences import org.microg.gms.checkin.CheckinService import org.microg.gms.checkin.LastCheckinInfo import org.microg.gms.common.ForegroundServiceContext @@ -29,7 +29,7 @@ import kotlin.coroutines.suspendCoroutine private const val TAG = "GmsGcmRegister" private suspend fun ensureCheckinIsUpToDate(context: Context) { - if (!CheckinPrefs.isEnabled(context)) throw RuntimeException("Checkin disabled") + if (!CheckinPreferences.isEnabled(context)) throw RuntimeException("Checkin disabled") val lastCheckin = LastCheckinInfo.read(context).lastCheckin if (lastCheckin < System.currentTimeMillis() - CheckinService.MAX_VALID_CHECKIN_AGE) { val resultData: Bundle = suspendCoroutine { continuation -> diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/AppHeadingPreference.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/AppHeadingPreference.kt new file mode 100644 index 00000000..c3cf6185 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/AppHeadingPreference.kt @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2023 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ +package org.microg.gms.ui +import android.content.Context +import android.content.Intent +import android.content.pm.ApplicationInfo +import android.net.Uri +import android.provider.Settings +import android.util.AttributeSet +import android.util.Log +import android.view.View +import android.widget.ImageView +import androidx.appcompat.content.res.AppCompatResources +import androidx.preference.Preference +import androidx.preference.PreferenceViewHolder +import org.microg.gms.base.core.R +class AppHeadingPreference : AppPreference, Preference.OnPreferenceClickListener { + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context) : super(context) + init { + layoutResource = R.layout.preference_app_heading + onPreferenceClickListener = this + } + override fun onPreferenceClick(preference: Preference): Boolean { + if (packageName != null) { + val intent = Intent() + intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS + val uri: Uri = Uri.fromParts("package", packageName, null) + intent.data = uri + try { + context.startActivity(intent) + } catch (e: Exception) { + Log.w(TAG, "Failed to launch app", e) + } + return true + } else { + return false + } + } +} \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/AppIconPreference.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/AppIconPreference.kt index de5020c0..1570c691 100755 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/AppIconPreference.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/AppIconPreference.kt @@ -11,8 +11,9 @@ import android.util.DisplayMetrics import android.widget.ImageView import androidx.preference.Preference import androidx.preference.PreferenceViewHolder +import android.content.pm.ApplicationInfo -class AppIconPreference : Preference { +class AppIconPreference : AppPreference { constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/AppPreference.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/AppPreference.kt new file mode 100644 index 00000000..27626231 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/AppPreference.kt @@ -0,0 +1,47 @@ +/* + * SPDX-FileCopyrightText: 2023 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ +package org.microg.gms.ui +import android.content.Context +import android.content.pm.ApplicationInfo +import android.util.AttributeSet +import androidx.appcompat.content.res.AppCompatResources +import androidx.preference.Preference +abstract class AppPreference : Preference { + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context) : super(context) + init { + isPersistent = false + } + private var packageNameField: String? = null + var applicationInfo: ApplicationInfo? + get() = context.packageManager.getApplicationInfoIfExists(packageNameField) + set(value) { + if (value == null && packageNameField != null) { + title = null + icon = null + } else if (value != null) { + val pm = context.packageManager + title = value.loadLabel(pm) ?: value.packageName + icon = value.loadIcon(pm) ?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon) + } + packageNameField = value?.packageName + } + var packageName: String? + get() = packageNameField + set(value) { + if (value == null && packageNameField != null) { + title = null + icon = null + } else if (value != null) { + val pm = context.packageManager + val applicationInfo = pm.getApplicationInfoIfExists(value) + title = applicationInfo?.loadLabel(pm)?.toString() ?: value + icon = applicationInfo?.loadIcon(pm) ?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon) + } + packageNameField = value + } +} \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationFragment.kt index 17887575..8c668529 100755 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationFragment.kt @@ -5,51 +5,163 @@ package org.microg.gms.ui + +import android.annotation.SuppressLint +import android.net.Uri import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment +import android.os.Handler +import android.text.format.DateUtils +import android.util.Log +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts import androidx.lifecycle.lifecycleScope +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceFragmentCompat import com.mgoogle.android.gms.R -import com.mgoogle.android.gms.databinding.DeviceRegistrationFragmentBinding -import org.microg.gms.checkin.ServiceInfo +import org.microg.gms.checkin.CheckinPreferences import org.microg.gms.checkin.getCheckinServiceInfo -import org.microg.gms.checkin.setCheckinServiceConfiguration +import org.microg.gms.profile.ProfileManager +import org.microg.gms.profile.ProfileManager.PROFILE_AUTO +import org.microg.gms.profile.ProfileManager.PROFILE_NATIVE +import org.microg.gms.profile.ProfileManager.PROFILE_REAL +import org.microg.gms.profile.ProfileManager.PROFILE_SYSTEM +import org.microg.gms.profile.ProfileManager.PROFILE_USER +import java.io.File +import java.io.FileOutputStream -class DeviceRegistrationFragment : Fragment(R.layout.device_registration_fragment) { - private lateinit var binding: DeviceRegistrationFragmentBinding +class DeviceRegistrationFragment : PreferenceFragmentCompat() { + private lateinit var switchBarPreference: SwitchBarPreference + private lateinit var deviceProfile: ListPreference + private lateinit var importProfile: Preference + private lateinit var serial: Preference + private lateinit var statusCategory: PreferenceCategory + private lateinit var status: Preference + private lateinit var androidId: Preference + private val handler = Handler() + private val updateRunnable = Runnable { updateStatus() } + private lateinit var profileFileImport: ActivityResultLauncher - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - binding = DeviceRegistrationFragmentBinding.inflate(inflater, container, false) - binding.switchBarCallback = object : PreferenceSwitchBarCallback { - override fun onChecked(newStatus: Boolean) { - setEnabled(newStatus) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + profileFileImport = registerForActivityResult(ActivityResultContracts.GetContent(), this::onFileSelected) + } + private fun onFileSelected(uri: Uri?) { + if (uri == null) return + try { + val context = requireContext() + val file = File.createTempFile("profile_", ".xml", context.cacheDir) + context.contentResolver.openInputStream(uri)?.use { inputStream -> + FileOutputStream(file).use { inputStream.copyTo(it) } + } + val success = ProfileManager.importUserProfile(context, file) + file.delete() + if (success && ProfileManager.isAutoProfile(context, PROFILE_USER)) { + ProfileManager.setProfile(context, PROFILE_USER) + } + updateStatus() + } catch (e: Exception) { + Log.w(TAG, e) + } + } + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.preferences_device_registration) + } + @SuppressLint("RestrictedApi") + override fun onBindPreferences() { + switchBarPreference = preferenceScreen.findPreference("pref_checkin_enabled") ?: switchBarPreference + deviceProfile = preferenceScreen.findPreference("pref_device_profile") ?: deviceProfile + importProfile = preferenceScreen.findPreference("pref_device_profile_import") ?: importProfile + serial = preferenceScreen.findPreference("pref_device_serial") ?: serial + statusCategory = preferenceScreen.findPreference("prefcat_device_registration_status") ?: statusCategory + status = preferenceScreen.findPreference("pref_device_registration_status") ?: status + androidId = preferenceScreen.findPreference("pref_device_registration_android_id") ?: androidId + deviceProfile.setOnPreferenceChangeListener { _, newValue -> + ProfileManager.setProfile(requireContext(), newValue as String? ?: PROFILE_AUTO) + updateStatus() + true + } + importProfile.setOnPreferenceClickListener { + profileFileImport.launch("text/xml") + true + } + switchBarPreference.setOnPreferenceChangeListener { _, newValue -> + val newStatus = newValue as Boolean + CheckinPreferences.setEnabled(requireContext(), newStatus) + true + } + } + private fun configureProfilePreference() { + val context = requireContext() + val configuredProfile = ProfileManager.getConfiguredProfile(context) + val autoProfile = ProfileManager.getAutoProfile(context) + val autoProfileName = when (autoProfile) { + PROFILE_NATIVE -> getString(R.string.profile_name_native) + PROFILE_REAL -> getString(R.string.profile_name_real) + else -> ProfileManager.getProfileName(context, autoProfile) + } + val profiles = + mutableListOf(PROFILE_AUTO, PROFILE_NATIVE, PROFILE_REAL) + val profileNames = mutableListOf(getString(R.string.profile_name_auto, autoProfileName), getString(R.string.profile_name_native), getString(R.string.profile_name_real)) + if (ProfileManager.hasProfile(context, PROFILE_SYSTEM)) { + profiles.add(PROFILE_SYSTEM) + profileNames.add(getString(R.string.profile_name_system, ProfileManager.getProfileName(context, PROFILE_SYSTEM))) + } + if (ProfileManager.hasProfile(context, PROFILE_USER)) { + profiles.add(PROFILE_USER) + profileNames.add(getString(R.string.profile_name_user, ProfileManager.getProfileName(context, PROFILE_USER))) + } + for (profile in R.xml::class.java.declaredFields.map { it.name } + .filter { it.startsWith("profile_") } + .map { it.substring(8) } + .sorted()) { + val profileName = ProfileManager.getProfileName(context, profile) + if (profileName != null) { + profiles.add(profile) + profileNames.add(profileName) } } - return binding.root - } - - fun setEnabled(newStatus: Boolean) { - val appContext = requireContext().applicationContext - lifecycleScope.launchWhenResumed { - val info = getCheckinServiceInfo(appContext) - val newConfiguration = info.configuration.copy(enabled = newStatus) - setCheckinServiceConfiguration(appContext, newConfiguration) - displayServiceInfo(info.copy(configuration = newConfiguration)) - } - } - - private fun displayServiceInfo(serviceInfo: ServiceInfo) { - binding.checkinEnabled = serviceInfo.configuration.enabled + deviceProfile.entryValues = profiles.toTypedArray() + deviceProfile.entries = profileNames.toTypedArray() + deviceProfile.value = configuredProfile + deviceProfile.summary = + profiles.indexOf(configuredProfile).takeIf { it >= 0 }?.let { profileNames[it] } ?: "Unknown" } override fun onResume() { super.onResume() + switchBarPreference.isChecked = CheckinPreferences.isEnabled(requireContext()) + updateStatus() + } + override fun onPause() { + super.onPause() + handler.removeCallbacks(updateRunnable) + } + private fun updateStatus() { + handler.removeCallbacks(updateRunnable) + handler.postDelayed(updateRunnable, UPDATE_INTERVAL) val appContext = requireContext().applicationContext lifecycleScope.launchWhenResumed { - displayServiceInfo(getCheckinServiceInfo(appContext)) + configureProfilePreference() + serial.summary = ProfileManager.getSerial(appContext) + val serviceInfo = getCheckinServiceInfo(appContext) + statusCategory.isVisible = serviceInfo.configuration.enabled + if (serviceInfo.lastCheckin > 0) { + status.summary = getString( + R.string.checkin_last_registration, + DateUtils.getRelativeTimeSpanString(serviceInfo.lastCheckin, System.currentTimeMillis(), 0) + ) + androidId.isVisible = true + androidId.summary = serviceInfo.androidId.toString(16) + } else { + status.summary = getString(R.string.checkin_not_registered) + androidId.isVisible = false + } } } + companion object { + private const val UPDATE_INTERVAL = 1000L + } } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt deleted file mode 100755 index ec274c5e..00000000 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt +++ /dev/null @@ -1,164 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020, microG Project Team - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.microg.gms.ui - -import android.annotation.SuppressLint -import android.net.Uri -import android.os.Bundle -import android.os.Handler -import android.text.format.DateUtils -import android.util.Log -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts -import androidx.lifecycle.lifecycleScope -import androidx.preference.ListPreference -import androidx.preference.Preference -import androidx.preference.PreferenceCategory -import androidx.preference.PreferenceFragmentCompat -import com.mgoogle.android.gms.R -import org.microg.gms.checkin.getCheckinServiceInfo -import org.microg.gms.profile.ProfileManager -import org.microg.gms.profile.ProfileManager.PROFILE_AUTO -import org.microg.gms.profile.ProfileManager.PROFILE_NATIVE -import org.microg.gms.profile.ProfileManager.PROFILE_REAL -import org.microg.gms.profile.ProfileManager.PROFILE_SYSTEM -import org.microg.gms.profile.ProfileManager.PROFILE_USER -import java.io.File -import java.io.FileOutputStream - -@Suppress("Warnings") -class DeviceRegistrationPreferencesFragment : PreferenceFragmentCompat() { - private lateinit var deviceProfile: ListPreference - private lateinit var importProfile: Preference - private lateinit var serial: Preference - private lateinit var statusCategory: PreferenceCategory - private lateinit var status: Preference - private lateinit var androidId: Preference - private val handler = Handler() - private val updateRunnable = Runnable { updateStatus() } - private lateinit var profileFileImport: ActivityResultLauncher - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - profileFileImport = registerForActivityResult(ActivityResultContracts.GetContent(), this::onFileSelected) - } - - private fun onFileSelected(uri: Uri?) { - if (uri == null) return - try { - val context = requireContext() - val file = File.createTempFile("profile_", ".xml", context.cacheDir) - context.contentResolver.openInputStream(uri)?.use { inputStream -> - FileOutputStream(file).use { inputStream.copyTo(it) } - } - val success = ProfileManager.importUserProfile(context, file) - file.delete() - if (success && ProfileManager.isAutoProfile(context, PROFILE_USER)) { - ProfileManager.setProfile(context, PROFILE_USER) - } - updateStatus() - } catch (e: Exception) { - Log.w(TAG, e) - } - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.preferences_device_registration) - } - - @SuppressLint("RestrictedApi") - override fun onBindPreferences() { - deviceProfile = preferenceScreen.findPreference("pref_device_profile") ?: deviceProfile - importProfile = preferenceScreen.findPreference("pref_device_profile_import") ?: importProfile - serial = preferenceScreen.findPreference("pref_device_serial") ?: serial - statusCategory = preferenceScreen.findPreference("prefcat_device_registration_status") ?: statusCategory - status = preferenceScreen.findPreference("pref_device_registration_status") ?: status - androidId = preferenceScreen.findPreference("pref_device_registration_android_id") ?: androidId - - deviceProfile.setOnPreferenceChangeListener { _, newValue -> - ProfileManager.setProfile(requireContext(), newValue as String? ?: PROFILE_AUTO) - updateStatus() - true - } - importProfile.setOnPreferenceClickListener { - profileFileImport.launch("text/xml") - true - } - } - - private fun configureProfilePreference() { - val context = requireContext() - val configuredProfile = ProfileManager.getConfiguredProfile(context) - val autoProfileName = when (val autoProfile = ProfileManager.getAutoProfile(context)) { - PROFILE_NATIVE -> getString(R.string.profile_name_native) - PROFILE_REAL -> getString(R.string.profile_name_real) - else -> ProfileManager.getProfileName(context, autoProfile) - } - val profiles = - mutableListOf(PROFILE_AUTO, PROFILE_NATIVE, PROFILE_REAL) - val profileNames = mutableListOf(getString(R.string.profile_name_auto, autoProfileName), getString(R.string.profile_name_native), getString(R.string.profile_name_real)) - if (ProfileManager.hasProfile(context, PROFILE_SYSTEM)) { - profiles.add(PROFILE_SYSTEM) - profileNames.add(getString(R.string.profile_name_system, ProfileManager.getProfileName(context, PROFILE_SYSTEM))) - } - if (ProfileManager.hasProfile(context, PROFILE_USER)) { - profiles.add(PROFILE_USER) - profileNames.add(getString(R.string.profile_name_user, ProfileManager.getProfileName(context, PROFILE_USER))) - } - for (profile in R.xml::class.java.declaredFields.map { it.name } - .filter { it.startsWith("profile_") } - .map { it.substring(8) } - .sorted()) { - val profileName = ProfileManager.getProfileName(context, profile) - if (profileName != null) { - profiles.add(profile) - profileNames.add(profileName) - } - } - deviceProfile.entryValues = profiles.toTypedArray() - deviceProfile.entries = profileNames.toTypedArray() - deviceProfile.value = configuredProfile - deviceProfile.summary = - profiles.indexOf(configuredProfile).takeIf { it >= 0 }?.let { profileNames[it] } ?: "Unknown" - } - - override fun onResume() { - super.onResume() - updateStatus() - } - - override fun onPause() { - super.onPause() - handler.removeCallbacks(updateRunnable) - } - - private fun updateStatus() { - handler.removeCallbacks(updateRunnable) - handler.postDelayed(updateRunnable, UPDATE_INTERVAL) - val appContext = requireContext().applicationContext - lifecycleScope.launchWhenResumed { - configureProfilePreference() - serial.summary = ProfileManager.getSerial(appContext) - val serviceInfo = getCheckinServiceInfo(appContext) - statusCategory.isVisible = serviceInfo.configuration.enabled - if (serviceInfo.lastCheckin > 0) { - status.summary = getString( - R.string.checkin_last_registration, - DateUtils.getRelativeTimeSpanString(serviceInfo.lastCheckin, System.currentTimeMillis(), 0) - ) - androidId.isVisible = true - androidId.summary = serviceInfo.androidId.toString(16) - } else { - status.summary = getString(R.string.checkin_not_registered) - androidId.isVisible = true - } - } - } - - companion object { - private const val UPDATE_INTERVAL = 1000L - } -} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PreferenceSwitchBarCallback.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PreferenceSwitchBarCallback.kt deleted file mode 100755 index b66f1119..00000000 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PreferenceSwitchBarCallback.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020, microG Project Team - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.microg.gms.ui - -interface PreferenceSwitchBarCallback { - fun onChecked(newStatus: Boolean) -} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAllAppsFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAllAppsFragment.kt index da3210e4..392e14d6 100755 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAllAppsFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAllAppsFragment.kt @@ -56,16 +56,12 @@ class PushNotificationAllAppsFragment : PreferenceFragmentCompat() { lifecycleScope.launchWhenResumed { val apps = withContext(Dispatchers.IO) { val res = database.appList.map { app -> - app to context.packageManager.getApplicationInfoIfExists(app.packageName) - }.map { (app, applicationInfo) -> val pref = AppIconPreference(context) - pref.title = applicationInfo?.loadLabel(context.packageManager) ?: app.packageName + pref.packageName = app.packageName pref.summary = when { app.lastMessageTimestamp > 0 -> getString(R.string.gcm_last_message_at, DateUtils.getRelativeTimeSpanString(app.lastMessageTimestamp)) else -> null } - pref.icon = applicationInfo?.loadIcon(context.packageManager) - ?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon) pref.onPreferenceClickListener = Preference.OnPreferenceClickListener { findNavController().navigate(requireContext(), R.id.openGcmAppDetailsFromAll, bundleOf( "package" to app.packageName diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppFragment.kt index f83a5e5d..780e85e1 100755 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppFragment.kt @@ -5,58 +5,135 @@ package org.microg.gms.ui -import android.content.Intent -import android.net.Uri +import android.annotation.SuppressLint import android.os.Bundle -import android.provider.Settings -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.appcompat.content.res.AppCompatResources -import androidx.fragment.app.Fragment +import android.text.format.DateUtils +import androidx.appcompat.app.AlertDialog import androidx.lifecycle.lifecycleScope +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.TwoStatePreference import com.mgoogle.android.gms.R -import com.mgoogle.android.gms.databinding.PushNotificationAppFragmentBinding +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.microg.gms.gcm.GcmDatabase +import org.microg.gms.gcm.PushRegisterManager +class PushNotificationAppFragment : PreferenceFragmentCompat() { + private lateinit var appHeadingPreference: AppHeadingPreference + private lateinit var wakeForDelivery: TwoStatePreference + private lateinit var allowRegister: TwoStatePreference + private lateinit var status: Preference + private lateinit var unregister: Preference + private lateinit var unregisterCat: PreferenceCategory -class PushNotificationAppFragment : Fragment(R.layout.push_notification_fragment) { - lateinit var binding: PushNotificationAppFragmentBinding - val packageName: String? + private lateinit var database: GcmDatabase + private val packageName: String? get() = arguments?.getString("package") - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - binding = PushNotificationAppFragmentBinding.inflate(inflater, container, false) - binding.callbacks = object : PushNotificationAppFragmentCallbacks { - override fun onAppClicked() { - val intent = Intent() - intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS - val uri: Uri = Uri.fromParts("package", packageName, null) - intent.data = uri - try { - context!!.startActivity(intent) - } catch (e: Exception) { - Log.w(TAG, "Failed to launch app", e) + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.preferences_push_notifications_app) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + database = GcmDatabase(context) + } + + @SuppressLint("RestrictedApi") + override fun onBindPreferences() { + appHeadingPreference = preferenceScreen.findPreference("pref_push_app_heading") ?: appHeadingPreference + wakeForDelivery = preferenceScreen.findPreference("pref_push_app_wake_for_delivery") ?: wakeForDelivery + allowRegister = preferenceScreen.findPreference("pref_push_app_allow_register") ?: allowRegister + unregister = preferenceScreen.findPreference("pref_push_app_unregister") ?: unregister + unregisterCat = preferenceScreen.findPreference("prefcat_push_app_unregister") ?: unregisterCat + status = preferenceScreen.findPreference("pref_push_app_status") ?: status + wakeForDelivery.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + database.setAppWakeForDelivery(packageName, newValue as Boolean) + database.close() + true + } + allowRegister.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + val enabled = newValue as? Boolean ?: return@OnPreferenceChangeListener false + if (!enabled) { + val registrations = packageName?.let { database.getRegistrationsByApp(it) } ?: emptyList() + if (registrations.isNotEmpty()) { + showUnregisterConfirm(R.string.gcm_unregister_after_deny_message) } } + database.setAppAllowRegister(packageName, enabled) + database.close() + true + } + unregister.onPreferenceClickListener = Preference.OnPreferenceClickListener { + showUnregisterConfirm(R.string.gcm_unregister_confirm_message) + true + } + } + + + private fun showUnregisterConfirm(unregisterConfirmDesc: Int) { + val pm = requireContext().packageManager + val applicationInfo = pm.getApplicationInfoIfExists(packageName) + AlertDialog.Builder(requireContext()) + .setTitle(getString(R.string.gcm_unregister_confirm_title, applicationInfo?.loadLabel(pm) + ?: packageName)) + .setMessage(unregisterConfirmDesc) + .setPositiveButton(android.R.string.yes) { _, _ -> unregister() } + .setNegativeButton(android.R.string.no) { _, _ -> }.show() + } + + private fun unregister() { + lifecycleScope.launchWhenResumed { + withContext(Dispatchers.IO) { + for (registration in database.getRegistrationsByApp(packageName)) { + PushRegisterManager.unregister(context, registration.packageName, registration.signature, null, null) + } + } + updateDetails() } - childFragmentManager.findFragmentById(R.id.sub_preferences)?.arguments = arguments - return binding.root } override fun onResume() { super.onResume() - val context = requireContext() + updateDetails() + } + + private fun updateDetails() { lifecycleScope.launchWhenResumed { - val pm = context.packageManager - val applicationInfo = pm.getApplicationInfoIfExists(packageName) - binding.appName = applicationInfo?.loadLabel(pm)?.toString() ?: packageName - binding.appIcon = applicationInfo?.loadIcon(pm) - ?: AppCompatResources.getDrawable(context, android.R.mipmap.sym_def_app_icon) + appHeadingPreference.packageName = packageName + val app = packageName?.let { database.getApp(it) } + wakeForDelivery.isChecked = app?.wakeForDelivery ?: true + allowRegister.isChecked = app?.allowRegister ?: true + val registrations = packageName?.let { database.getRegistrationsByApp(it) } ?: emptyList() + unregisterCat.isVisible = registrations.isNotEmpty() + + val sb = StringBuilder() + if ((app?.totalMessageCount ?: 0L) == 0L) { + sb.append(getString(R.string.gcm_no_message_yet)) + } else { + sb.append(getString(R.string.gcm_messages_counter, app?.totalMessageCount, app?.totalMessageBytes)) + if (app?.lastMessageTimestamp != 0L) { + sb.append("\n").append(getString(R.string.gcm_last_message_at, DateUtils.getRelativeDateTimeString(context, app?.lastMessageTimestamp ?: 0L, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME))) + } + } + for (registration in registrations) { + sb.append("\n") + if (registration.timestamp == 0L) { + sb.append(getString(R.string.gcm_registered)) + } else { + sb.append(getString(R.string.gcm_registered_since, DateUtils.getRelativeDateTimeString(context, registration.timestamp, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME))) + } + } + status.summary = sb.toString() + + database.close() } } -} -interface PushNotificationAppFragmentCallbacks { - fun onAppClicked() -} + override fun onPause() { + super.onPause() + database.close() + } +} \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppPreferencesFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppPreferencesFragment.kt deleted file mode 100755 index 7106e506..00000000 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAppPreferencesFragment.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020, microG Project Team - * SPDX-License-Identifier: Apache-2.0 - */ -@file:Suppress("DEPRECATION") - -package org.microg.gms.ui - -import android.annotation.SuppressLint -import android.os.Bundle -import android.text.format.DateUtils -import androidx.appcompat.app.AlertDialog -import androidx.lifecycle.lifecycleScope -import androidx.preference.Preference -import androidx.preference.PreferenceCategory -import androidx.preference.PreferenceFragmentCompat -import androidx.preference.TwoStatePreference -import com.mgoogle.android.gms.R -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.microg.gms.gcm.GcmDatabase -import org.microg.gms.gcm.PushRegisterManager - -class PushNotificationAppPreferencesFragment : PreferenceFragmentCompat() { - private lateinit var wakeForDelivery: TwoStatePreference - private lateinit var allowRegister: TwoStatePreference - private lateinit var status: Preference - private lateinit var unregister: Preference - private lateinit var unregisterCat: PreferenceCategory - - private lateinit var database: GcmDatabase - private val packageName: String? - get() = arguments?.getString("package") - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.preferences_push_notifications_app) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - database = GcmDatabase(context) - } - - @SuppressLint("RestrictedApi") - override fun onBindPreferences() { - wakeForDelivery = preferenceScreen.findPreference("pref_push_app_wake_for_delivery") ?: wakeForDelivery - allowRegister = preferenceScreen.findPreference("pref_push_app_allow_register") ?: allowRegister - unregister = preferenceScreen.findPreference("pref_push_app_unregister") ?: unregister - unregisterCat = preferenceScreen.findPreference("prefcat_push_app_unregister") ?: unregisterCat - status = preferenceScreen.findPreference("pref_push_app_status") ?: status - wakeForDelivery.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> - database.setAppWakeForDelivery(packageName, newValue as Boolean) - database.close() - true - } - allowRegister.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> - val enabled = newValue as? Boolean ?: return@OnPreferenceChangeListener false - if (!enabled) { - val registrations = packageName?.let { database.getRegistrationsByApp(it) } ?: emptyList() - if (registrations.isNotEmpty()) { - showUnregisterConfirm(R.string.gcm_unregister_after_deny_message) - } - } - database.setAppAllowRegister(packageName, enabled) - database.close() - true - } - unregister.onPreferenceClickListener = Preference.OnPreferenceClickListener { - showUnregisterConfirm(R.string.gcm_unregister_confirm_message) - true - } - } - - - private fun showUnregisterConfirm(unregisterConfirmDesc: Int) { - val pm = requireContext().packageManager - val applicationInfo = pm.getApplicationInfoIfExists(packageName) - AlertDialog.Builder(requireContext()) - .setTitle(getString(R.string.gcm_unregister_confirm_title, applicationInfo?.loadLabel(pm) - ?: packageName)) - .setMessage(unregisterConfirmDesc) - .setPositiveButton(android.R.string.yes) { _, _ -> unregister() } - .setNegativeButton(android.R.string.no) { _, _ -> }.show() - } - - private fun unregister() { - lifecycleScope.launchWhenResumed { - withContext(Dispatchers.IO) { - for (registration in database.getRegistrationsByApp(packageName)) { - PushRegisterManager.unregister(context, registration.packageName, registration.signature, null, null) - } - } - updateDetails() - } - } - - override fun onResume() { - super.onResume() - updateDetails() - } - - private fun updateDetails() { - lifecycleScope.launchWhenResumed { - val app = packageName?.let { database.getApp(it) } - wakeForDelivery.isChecked = app?.wakeForDelivery ?: true - allowRegister.isChecked = app?.allowRegister ?: true - val registrations = packageName?.let { database.getRegistrationsByApp(it) } ?: emptyList() - unregisterCat.isVisible = registrations.isNotEmpty() - - val sb = StringBuilder() - if ((app?.totalMessageCount ?: 0L) == 0L) { - sb.append(getString(R.string.gcm_no_message_yet)) - } else { - sb.append(getString(R.string.gcm_messages_counter, app?.totalMessageCount, app?.totalMessageBytes)) - if (app?.lastMessageTimestamp != 0L) { - sb.append("\n").append(getString(R.string.gcm_last_message_at, DateUtils.getRelativeDateTimeString(context, app?.lastMessageTimestamp ?: 0L, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME))) - } - } - for (registration in registrations) { - sb.append("\n") - if (registration.timestamp == 0L) { - sb.append(getString(R.string.gcm_registered)) - } else { - sb.append(getString(R.string.gcm_registered_since, DateUtils.getRelativeDateTimeString(context, registration.timestamp, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME))) - } - } - status.summary = sb.toString() - - database.close() - } - } - - override fun onPause() { - super.onPause() - database.close() - } -} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt index cb5aaa18..d05afb3d 100755 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt @@ -2,61 +2,142 @@ * SPDX-FileCopyrightText: 2020, microG Project Team * SPDX-License-Identifier: Apache-2.0 */ + package org.microg.gms.ui +import android.annotation.SuppressLint import android.os.Bundle -import android.view.* -import androidx.fragment.app.Fragment +import android.os.Handler +import android.text.format.DateUtils +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import androidx.core.os.bundleOf import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceFragmentCompat import com.mgoogle.android.gms.R -import com.mgoogle.android.gms.databinding.PushNotificationFragmentBinding -import org.microg.gms.checkin.getCheckinServiceInfo -import org.microg.gms.gcm.ServiceInfo +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.microg.gms.checkin.CheckinPreferences +import org.microg.gms.gcm.GcmDatabase +import org.microg.gms.gcm.GcmPrefs import org.microg.gms.gcm.getGcmServiceInfo -import org.microg.gms.gcm.setGcmServiceConfiguration -@Suppress("Warnings") -class PushNotificationFragment : Fragment(R.layout.push_notification_fragment) { - lateinit var binding: PushNotificationFragmentBinding +class PushNotificationFragment : PreferenceFragmentCompat() { + private lateinit var switchBarPreference: SwitchBarPreference + private lateinit var pushStatusCategory: PreferenceCategory + private lateinit var pushStatus: Preference + private lateinit var pushApps: PreferenceCategory + private lateinit var pushAppsAll: Preference + private lateinit var pushAppsNone: Preference + private lateinit var database: GcmDatabase + private val handler = Handler() + private val updateRunnable = Runnable { updateStatus() } - init { - setHasOptionsMenu(true) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + database = GcmDatabase(context) } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - binding = PushNotificationFragmentBinding.inflate(inflater, container, false) - binding.switchBarCallback = object : PreferenceSwitchBarCallback { - override fun onChecked(newStatus: Boolean) { - setEnabled(newStatus) - } + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.preferences_push_notifications) + } + + @SuppressLint("RestrictedApi") + override fun onBindPreferences() { + switchBarPreference = preferenceScreen.findPreference("pref_push_enabled") ?: switchBarPreference + pushStatusCategory = preferenceScreen.findPreference("prefcat_push_status") ?: pushStatusCategory + pushStatus = preferenceScreen.findPreference("pref_push_status") ?: pushStatus + pushApps = preferenceScreen.findPreference("prefcat_push_apps") ?: pushApps + pushAppsAll = preferenceScreen.findPreference("pref_push_apps_all") ?: pushAppsAll + pushAppsNone = preferenceScreen.findPreference("pref_push_apps_none") ?: pushAppsNone + pushAppsAll.setOnPreferenceClickListener { + findNavController().navigate(requireContext(), R.id.openAllGcmApps) + true } - return binding.root - } - - fun setEnabled(newStatus: Boolean) { - val appContext = requireContext().applicationContext - lifecycleScope.launchWhenResumed { - val info = getGcmServiceInfo(appContext) - val newConfiguration = info.configuration.copy(enabled = newStatus) - setGcmServiceConfiguration(appContext, newConfiguration) - displayServiceInfo(info.copy(configuration = newConfiguration)) + switchBarPreference.setOnPreferenceChangeListener { _, newValue -> + val newStatus = newValue as Boolean + GcmPrefs.setEnabled(requireContext(), newStatus) + true } } - private fun displayServiceInfo(serviceInfo: ServiceInfo) { - binding.gcmEnabled = serviceInfo.configuration.enabled - } - override fun onResume() { super.onResume() + + switchBarPreference.isEnabled = CheckinPreferences.isEnabled(requireContext()) + switchBarPreference.isChecked = GcmPrefs.get(requireContext()).isEnabled + + updateStatus() + updateContent() + } + + override fun onPause() { + super.onPause() + database.close() + handler.removeCallbacks(updateRunnable) + } + + private fun updateStatus() { + handler.postDelayed(updateRunnable, UPDATE_INTERVAL) val appContext = requireContext().applicationContext - lifecycleScope.launchWhenResumed { - displayServiceInfo(getGcmServiceInfo(appContext)) - binding.checkinEnabled = getCheckinServiceInfo(appContext).configuration.enabled + lifecycleScope.launchWhenStarted { + val statusInfo = getGcmServiceInfo(appContext) + switchBarPreference.isChecked = statusInfo.configuration.enabled + pushStatusCategory.isVisible = statusInfo != null && statusInfo.configuration.enabled + pushStatus.summary = if (statusInfo != null && statusInfo.connected) { + appContext.getString(R.string.gcm_network_state_connected, DateUtils.getRelativeTimeSpanString(statusInfo.startTimestamp, System.currentTimeMillis(), 0)) + } else { + appContext.getString(R.string.gcm_network_state_disconnected) + } } } + private fun updateContent() { + lifecycleScope.launchWhenResumed { + val context = requireContext() + val (apps, showAll) = withContext(Dispatchers.IO) { + val apps = database.appList.sortedByDescending { it.lastMessageTimestamp } + val res = apps.map { app -> + app to context.packageManager.getApplicationInfoIfExists(app.packageName) + }.mapNotNull { (app, info) -> + if (info == null) null else app to info + }.take(3).mapIndexed { idx, (app, applicationInfo) -> + val pref = AppIconPreference(context) + pref.order = idx + pref.applicationInfo = applicationInfo + pref.onPreferenceClickListener = Preference.OnPreferenceClickListener { + findNavController().navigate(requireContext(), R.id.openGcmAppDetails, bundleOf( + "package" to app.packageName + )) + true + } + pref.key = "pref_push_app_" + app.packageName + pref + }.let { it to (it.size < apps.size) } + database.close() + res + } + pushAppsAll.isVisible = showAll + pushApps.removeAll() + for (app in apps) { + pushApps.addPreference(app) + } + if (showAll) { + pushApps.addPreference(pushAppsAll) + } else if (apps.isEmpty()) { + pushApps.addPreference(pushAppsNone) + } + } + } + + init { + setHasOptionsMenu(true) + } + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { menu.add(0, MENU_ADVANCED, 0, R.string.menu_advanced) super.onCreateOptionsMenu(menu, inflater) @@ -73,7 +154,7 @@ class PushNotificationFragment : Fragment(R.layout.push_notification_fragment) { } companion object { + private const val UPDATE_INTERVAL = 1000L private const val MENU_ADVANCED = Menu.FIRST } -} - +} \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationPreferencesFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationPreferencesFragment.kt deleted file mode 100755 index da861c0b..00000000 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationPreferencesFragment.kt +++ /dev/null @@ -1,128 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020, microG Project Team - * SPDX-License-Identifier: Apache-2.0 - */ -@file:Suppress("DEPRECATION") - -package org.microg.gms.ui - -import android.annotation.SuppressLint -import android.os.Bundle -import android.os.Handler -import android.text.format.DateUtils -import androidx.core.os.bundleOf -import androidx.lifecycle.lifecycleScope -import androidx.navigation.fragment.findNavController -import androidx.preference.Preference -import androidx.preference.PreferenceCategory -import androidx.preference.PreferenceFragmentCompat -import com.mgoogle.android.gms.R -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.microg.gms.gcm.GcmDatabase -import org.microg.gms.gcm.getGcmServiceInfo - -class PushNotificationPreferencesFragment : PreferenceFragmentCompat() { - private lateinit var pushStatusCategory: PreferenceCategory - private lateinit var pushStatus: Preference - private lateinit var pushApps: PreferenceCategory - private lateinit var pushAppsAll: Preference - private lateinit var pushAppsNone: Preference - private lateinit var database: GcmDatabase - private val handler = Handler() - private val updateRunnable = Runnable { updateStatus() } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - database = GcmDatabase(context) - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.preferences_push_notifications) - } - - @SuppressLint("RestrictedApi") - override fun onBindPreferences() { - pushStatusCategory = preferenceScreen.findPreference("prefcat_push_status") ?: pushStatusCategory - pushStatus = preferenceScreen.findPreference("pref_push_status") ?: pushStatus - pushApps = preferenceScreen.findPreference("prefcat_push_apps") ?: pushApps - pushAppsAll = preferenceScreen.findPreference("pref_push_apps_all") ?: pushAppsAll - pushAppsNone = preferenceScreen.findPreference("pref_push_apps_none") ?: pushAppsNone - pushAppsAll.onPreferenceClickListener = Preference.OnPreferenceClickListener { - findNavController().navigate(requireContext(), R.id.openAllGcmApps) - true - } - } - - override fun onResume() { - super.onResume() - updateStatus() - updateContent() - } - - override fun onPause() { - super.onPause() - database.close() - handler.removeCallbacks(updateRunnable) - } - - private fun updateStatus() { - try { - handler.postDelayed(updateRunnable, UPDATE_INTERVAL) - val appContext = requireContext().applicationContext - lifecycleScope.launchWhenStarted { - val statusInfo = getGcmServiceInfo(appContext) - pushStatusCategory.isVisible = statusInfo.configuration.enabled - pushStatus.summary = if (statusInfo.connected) { - getString(R.string.gcm_network_state_connected, DateUtils.getRelativeTimeSpanString(statusInfo.startTimestamp, System.currentTimeMillis(), 0)) - } else { - getString(R.string.gcm_network_state_disconnected) - } - } - } catch (_: Exception) {} - } - - private fun updateContent() { - val appContext = requireContext().applicationContext - val context = requireContext() - lifecycleScope.launchWhenResumed { - val (apps, showAll) = withContext(Dispatchers.IO) { - val apps = database.appList.sortedByDescending { it.lastMessageTimestamp } - val res = apps.map { app -> - app to appContext.packageManager.getApplicationInfoIfExists(app.packageName) - }.mapNotNull { (app, info) -> - if (info == null) null else app to info - }.take(3).mapIndexed { idx, (app, applicationInfo) -> - val pref = AppIconPreference(appContext) - pref.order = idx - pref.title = applicationInfo.loadLabel(appContext.packageManager) - pref.icon = applicationInfo.loadIcon(appContext.packageManager) - pref.onPreferenceClickListener = Preference.OnPreferenceClickListener { - findNavController().navigate(context, R.id.openGcmAppDetails, bundleOf( - "package" to app.packageName - )) - true - } - pref.key = "pref_push_app_" + app.packageName - pref - }.let { it to (it.size < apps.size) } - database.close() - res - } - pushAppsAll.isVisible = showAll - pushApps.removeAll() - for (app in apps) { - pushApps.addPreference(app) - } - if (showAll) { - pushApps.addPreference(pushAppsAll) - } else if (apps.isEmpty()) { - pushApps.addPreference(pushAppsNone) - } - } - } - - companion object { - private const val UPDATE_INTERVAL = 1000L - } -} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt index e8cf7051..fe98a953 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt @@ -15,7 +15,7 @@ import androidx.preference.Preference import androidx.preference.PreferenceCategory import androidx.preference.SwitchPreferenceCompat import com.mgoogle.android.gms.R -import org.microg.gms.checkin.CheckinPrefs +import org.microg.gms.checkin.CheckinPreferences import org.microg.gms.gcm.GcmDatabase import org.microg.gms.gcm.GcmPrefs import org.microg.gms.settings.SettingsContract @@ -112,7 +112,7 @@ class SettingsFragment : ResourceSettingsFragment() { findPreference(PREF_GCM)?.setSummary(R.string.service_status_disabled_short) } - findPreference(PREF_CHECKIN)?.setSummary(if (CheckinPrefs.isEnabled(context)) R.string.service_status_enabled_short else R.string.service_status_disabled_short) + findPreference(PREF_CHECKIN)?.setSummary(if (CheckinPreferences.isEnabled(context)) R.string.service_status_enabled_short else R.string.service_status_disabled_short) findPreference(PREF_PLAY)!!.setSummary(if (PlayPreferences.isLicensingEnabled(requireContext())) R.string.pref_play_summary_licensing_on else R.string.pref_play_summary_licensing_off) lifecycleScope.launchWhenResumed { diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/SwitchBarPreference.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/SwitchBarPreference.kt new file mode 100644 index 00000000..12802a1e --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/SwitchBarPreference.kt @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2023 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.ui + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.SwitchCompat +import androidx.preference.PreferenceViewHolder +import androidx.preference.TwoStatePreference +import org.microg.gms.base.core.R + +// TODO +class SwitchBarPreference : TwoStatePreference { + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context) : super(context) + + init { + layoutResource = R.layout.preference_switch_bar + } + + override fun onBindViewHolder(holder: PreferenceViewHolder) { + super.onBindViewHolder(holder) + holder.isDividerAllowedBelow = false + holder.isDividerAllowedAbove = false + val switch = holder.findViewById(R.id.switch_widget) as SwitchCompat + switch.setOnCheckedChangeListener(null) + switch.isChecked = isChecked + switch.setOnCheckedChangeListener { view, isChecked -> + if (!callChangeListener(isChecked)) { + view.isChecked = !isChecked + return@setOnCheckedChangeListener + } + this.isChecked = isChecked + } + holder.itemView.setBackgroundColor(when { + isChecked -> androidx.appcompat.R.attr.colorControlActivated + isEnabled -> androidx.appcompat.R.attr.colorButtonNormal + else -> androidx.appcompat.R.attr.colorControlHighlight + }) + } +} + +@Deprecated("Get rid") +interface PreferenceSwitchBarCallback { + fun onChecked(newStatus: Boolean) +} \ No newline at end of file diff --git a/play-services-core/src/main/res/layout/device_registration_fragment.xml b/play-services-core/src/main/res/layout/device_registration_fragment.xml deleted file mode 100755 index fe6d1e51..00000000 --- a/play-services-core/src/main/res/layout/device_registration_fragment.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/play-services-core/src/main/res/layout/preference_app_heading.xml b/play-services-core/src/main/res/layout/preference_app_heading.xml new file mode 100644 index 00000000..cb7e4edf --- /dev/null +++ b/play-services-core/src/main/res/layout/preference_app_heading.xml @@ -0,0 +1,43 @@ + + + + + + + \ No newline at end of file diff --git a/play-services-core/src/main/res/layout/preference_switch_bar.xml b/play-services-core/src/main/res/layout/preference_switch_bar.xml index 346b1dd4..9818305b 100755 --- a/play-services-core/src/main/res/layout/preference_switch_bar.xml +++ b/play-services-core/src/main/res/layout/preference_switch_bar.xml @@ -1,71 +1,42 @@ - - - + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:gravity="center" + android:orientation="horizontal" + android:paddingStart="?attr/listPreferredItemPaddingStart" + android:paddingLeft="?attr/listPreferredItemPaddingLeft" + android:paddingEnd="?attr/listPreferredItemPaddingEnd" + android:paddingRight="?attr/listPreferredItemPaddingRight" + tools:background="?attr/colorControlActivated"> - + - - - - - - - - - - - - - - - - + app:thumbTint="?android:attr/textColorPrimaryInverse" + app:trackTint="?android:attr/textColorSecondaryInverse" + tools:checked="true" /> + \ No newline at end of file diff --git a/play-services-core/src/main/res/layout/push_notification_app_fragment.xml b/play-services-core/src/main/res/layout/push_notification_app_fragment.xml deleted file mode 100755 index dcc6e7ad..00000000 --- a/play-services-core/src/main/res/layout/push_notification_app_fragment.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/play-services-core/src/main/res/layout/push_notification_fragment.xml b/play-services-core/src/main/res/layout/push_notification_fragment.xml deleted file mode 100755 index fdd799bd..00000000 --- a/play-services-core/src/main/res/layout/push_notification_fragment.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/play-services-core/src/main/res/xml/preferences_device_registration.xml b/play-services-core/src/main/res/xml/preferences_device_registration.xml index 4935bfb8..3fa45eb5 100755 --- a/play-services-core/src/main/res/xml/preferences_device_registration.xml +++ b/play-services-core/src/main/res/xml/preferences_device_registration.xml @@ -5,7 +5,14 @@ --> + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + + diff --git a/play-services-core/src/main/res/xml/preferences_push_notifications.xml b/play-services-core/src/main/res/xml/preferences_push_notifications.xml index 9c250f95..416cfac8 100755 --- a/play-services-core/src/main/res/xml/preferences_push_notifications.xml +++ b/play-services-core/src/main/res/xml/preferences_push_notifications.xml @@ -7,6 +7,11 @@ + + diff --git a/play-services-core/src/main/res/xml/preferences_push_notifications_app.xml b/play-services-core/src/main/res/xml/preferences_push_notifications_app.xml index 01d83e52..5cf81e5b 100755 --- a/play-services-core/src/main/res/xml/preferences_push_notifications_app.xml +++ b/play-services-core/src/main/res/xml/preferences_push_notifications_app.xml @@ -6,6 +6,11 @@ + + From 299785daafeb1cc18115e88ee6b72fb06aa88f1f Mon Sep 17 00:00:00 2001 From: cuynu Date: Sat, 22 Mar 2025 15:34:55 +0700 Subject: [PATCH 23/29] up gradle 8.1 --- gradle/wrapper/gradle-wrapper.properties | 3 ++- gradlew | 29 ++++++++++++++---------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 42defcc9..0e1ae8ce 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 65dcd68d..1aa94a42 100755 --- a/gradlew +++ b/gradlew @@ -83,10 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +131,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ From d65e8c359c67500b0e41f2fc0a5c0285466beb7e Mon Sep 17 00:00:00 2001 From: cuynu Date: Sat, 22 Mar 2025 15:35:49 +0700 Subject: [PATCH 24/29] bump 25.09.34 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 01047d0b..bcf0bcbe 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ buildscript { } -def gmsVersion = "24.38.32" +def gmsVersion = "25.09.34" def gmsVersionCode = Integer.parseInt(gmsVersion.replaceAll('\\.', '')) def ourVersionBase = "0.3.0" From d55ee374adcf20ac907b389ed9bdf5b5ffeb530c Mon Sep 17 00:00:00 2001 From: cuynu Date: Sat, 22 Mar 2025 15:48:45 +0700 Subject: [PATCH 25/29] make back to vanced+ option clickable --- .../src/main/res/xml/preferences_google_more.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/play-services-core/src/main/res/xml/preferences_google_more.xml b/play-services-core/src/main/res/xml/preferences_google_more.xml index 0d348123..69ff3a86 100755 --- a/play-services-core/src/main/res/xml/preferences_google_more.xml +++ b/play-services-core/src/main/res/xml/preferences_google_more.xml @@ -75,7 +75,6 @@ android:title="@string/pref_auth_include_android_id_title"/> + android:summary="DD MM YYYY - monthly"> From ef31eda600ada5eb49543964eb22855615fa045c Mon Sep 17 00:00:00 2001 From: cuynu Date: Sat, 22 Mar 2025 15:51:40 +0700 Subject: [PATCH 26/29] Revert "Add preference for play licensing `microg@4ef2248`" This reverts commit 9a12599b --- gradle/wrapper/gradle-wrapper.jar | Bin 61624 -> 43462 bytes .../microg/gms/settings/SettingsContract.kt | 11 ----- .../microg/gms/settings/SettingsProvider.kt | 21 --------- .../org/microg/gms/play/PlayPreferences.kt | 18 -------- .../kotlin/org/microg/gms/ui/PlayFragment.kt | 42 ------------------ .../src/main/res/navigation/nav_settings.xml | 10 ----- .../src/main/res/values-ar/strings.xml | 5 --- .../src/main/res/values-az/strings.xml | 5 --- .../src/main/res/values-be/strings.xml | 5 --- .../src/main/res/values-bn/strings.xml | 5 --- .../src/main/res/values-cs/strings.xml | 5 --- .../src/main/res/values-es-rES/strings.xml | 5 --- .../src/main/res/values-fr/strings.xml | 5 --- .../src/main/res/values-he/strings.xml | 5 --- .../src/main/res/values-hi/strings.xml | 5 --- .../src/main/res/values-id/strings.xml | 5 --- .../src/main/res/values-it/strings.xml | 5 --- .../src/main/res/values-ja/strings.xml | 5 --- .../src/main/res/values-ko/strings.xml | 5 --- .../src/main/res/values-lt/strings.xml | 5 --- .../src/main/res/values-pt-rBR/strings.xml | 5 --- .../src/main/res/values-ru/strings.xml | 5 --- .../src/main/res/values-th/strings.xml | 5 --- .../src/main/res/values-tr/strings.xml | 5 --- .../src/main/res/values-uk/strings.xml | 5 --- .../src/main/res/values-vi/strings.xml | 5 --- .../src/main/res/values-zh-rCN/strings.xml | 5 --- .../src/main/res/values-zh-rTW/strings.xml | 5 --- .../src/main/res/values/strings.xml | 7 +-- .../src/main/res/xml/preferences_play.xml | 12 ----- .../src/main/res/xml/preferences_start.xml | 5 --- 31 files changed, 2 insertions(+), 234 deletions(-) delete mode 100644 play-services-core/src/main/kotlin/org/microg/gms/play/PlayPreferences.kt delete mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/PlayFragment.kt delete mode 100644 play-services-core/src/main/res/xml/preferences_play.xml diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index afba109285af78dbd2a1d187e33ac4f87c76e392..d64cd4917707c1f8861d8cb53dd15194d4248596 100644 GIT binary patch literal 43462 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

l-wUqma}v2c(1Oi^~*7`Q^d3B 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 literal 61624 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 diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt index 031b178d..8851d1a1 100644 --- a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt +++ b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt @@ -103,17 +103,6 @@ object SettingsContract { ) } - object Play { - private const val id = "play" - fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id) - fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id" - const val LICENSING = "play_licensing" - val PROJECTION = arrayOf( - LICENSING - ) - } - - private fun withoutCallingIdentity(f: () -> T): T { val identity = Binder.clearCallingIdentity() try { diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt index 15b797e3..39dc00e1 100644 --- a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt +++ b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt @@ -14,7 +14,6 @@ import android.content.SharedPreferences import android.database.Cursor import android.database.MatrixCursor import android.net.Uri -import org.microg.gms.settings.SettingsContract.Play import android.preference.PreferenceManager import org.microg.gms.common.PackageUtils.warnIfNotMainProcess import org.microg.gms.settings.SettingsContract.Auth @@ -69,7 +68,6 @@ class SettingsProvider : ContentProvider() { Gcm.getContentUri(context!!) -> queryGcm(projection ?: Gcm.PROJECTION) Auth.getContentUri(context!!) -> queryAuth(projection ?: Auth.PROJECTION) Profile.getContentUri(context!!) -> queryProfile(projection ?: Profile.PROJECTION) - Play.getContentUri(context!!) -> queryPlay(projection ?: Play.PROJECTION) else -> null } @@ -86,30 +84,11 @@ class SettingsProvider : ContentProvider() { Gcm.getContentUri(context!!) -> updateGcm(values) Auth.getContentUri(context!!) -> updateAuth(values) Profile.getContentUri(context!!) -> updateProfile(values) - Play.getContentUri(context!!) -> updatePlay(values) else -> return 0 } return 1 } - private fun queryPlay(p: Array): Cursor = MatrixCursor(p).addRow(p) { key -> - when (key) { - Play.LICENSING -> getSettingsBoolean(key, false) - else -> throw IllegalArgumentException("Unknown key: $key") - } - } - private fun updatePlay(values: ContentValues) { - if (values.size() == 0) return - val editor = preferences.edit() - values.valueSet().forEach { (key, value) -> - when (key) { - Play.LICENSING -> editor.putBoolean(key, value as Boolean) - else -> throw IllegalArgumentException("Unknown key: $key") - } - } - editor.apply() - } - private fun queryCheckIn(p: Array): Cursor = MatrixCursor(p).addRow(p) { key -> when (key) { CheckIn.ENABLED -> getSettingsBoolean(key, true) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/play/PlayPreferences.kt b/play-services-core/src/main/kotlin/org/microg/gms/play/PlayPreferences.kt deleted file mode 100644 index fa906104..00000000 --- a/play-services-core/src/main/kotlin/org/microg/gms/play/PlayPreferences.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.microg.gms.play -import android.content.Context -import org.microg.gms.settings.SettingsContract -object PlayPreferences { - @JvmStatic - fun isLicensingEnabled(context: Context): Boolean { - val projection = arrayOf(SettingsContract.Play.LICENSING) - return SettingsContract.getSettings(context, SettingsContract.Play.getContentUri(context), projection) { c -> - c.getInt(0) != 0 - } - } - @JvmStatic - fun setLicensingEnabled(context: Context, enabled: Boolean) { - SettingsContract.setSettings(context, SettingsContract.Play.getContentUri(context)) { - put(SettingsContract.Play.LICENSING, enabled) - } - } -} \ No newline at end of file diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PlayFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PlayFragment.kt deleted file mode 100644 index eb7f1515..00000000 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PlayFragment.kt +++ /dev/null @@ -1,42 +0,0 @@ -package org.microg.gms.ui -import android.annotation.SuppressLint -import android.os.Bundle -import androidx.lifecycle.lifecycleScope -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import androidx.preference.TwoStatePreference -import com.mgoogle.android.gms.R -import org.microg.gms.play.PlayPreferences -class PlayFragment : PreferenceFragmentCompat() { - private lateinit var licensingEnabled: TwoStatePreference - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.preferences_play) - } - @SuppressLint("RestrictedApi") - override fun onBindPreferences() { - licensingEnabled = preferenceScreen.findPreference(PREF_LICENSING_ENABLED) ?: licensingEnabled - licensingEnabled.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> - val appContext = requireContext().applicationContext - lifecycleScope.launchWhenResumed { - if (newValue is Boolean) { - PlayPreferences.setLicensingEnabled(appContext, newValue) - } - updateContent() - } - true - } - } - override fun onResume() { - super.onResume() - updateContent() - } - private fun updateContent() { - val appContext = requireContext().applicationContext - lifecycleScope.launchWhenResumed { - licensingEnabled.isChecked = PlayPreferences.isLicensingEnabled(appContext) - } - } - companion object { - const val PREF_LICENSING_ENABLED = "play_licensing" - } -} \ No newline at end of file diff --git a/play-services-core/src/main/res/navigation/nav_settings.xml b/play-services-core/src/main/res/navigation/nav_settings.xml index fd1a42ff..fb1cfa00 100755 --- a/play-services-core/src/main/res/navigation/nav_settings.xml +++ b/play-services-core/src/main/res/navigation/nav_settings.xml @@ -11,9 +11,6 @@ - - - diff --git a/play-services-core/src/main/res/values-ar/strings.xml b/play-services-core/src/main/res/values-ar/strings.xml index 0043af17..5d4cd8ea 100644 --- a/play-services-core/src/main/res/values-ar/strings.xml +++ b/play-services-core/src/main/res/values-ar/strings.xml @@ -138,9 +138,4 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-az/strings.xml b/play-services-core/src/main/res/values-az/strings.xml index 500e7ea7..740a9b11 100644 --- a/play-services-core/src/main/res/values-az/strings.xml +++ b/play-services-core/src/main/res/values-az/strings.xml @@ -138,9 +138,4 @@ Bu bir neçə dəqiqə çəkə bilər." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-be/strings.xml b/play-services-core/src/main/res/values-be/strings.xml index 339f72ea..1152301e 100644 --- a/play-services-core/src/main/res/values-be/strings.xml +++ b/play-services-core/src/main/res/values-be/strings.xml @@ -138,9 +138,4 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-bn/strings.xml b/play-services-core/src/main/res/values-bn/strings.xml index 2c33052f..0156013d 100644 --- a/play-services-core/src/main/res/values-bn/strings.xml +++ b/play-services-core/src/main/res/values-bn/strings.xml @@ -139,9 +139,4 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-cs/strings.xml b/play-services-core/src/main/res/values-cs/strings.xml index df04f144..7e021dd8 100644 --- a/play-services-core/src/main/res/values-cs/strings.xml +++ b/play-services-core/src/main/res/values-cs/strings.xml @@ -135,9 +135,4 @@ Tato akce může trvat několik minut." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-es-rES/strings.xml b/play-services-core/src/main/res/values-es-rES/strings.xml index ef2e4b05..5b090832 100644 --- a/play-services-core/src/main/res/values-es-rES/strings.xml +++ b/play-services-core/src/main/res/values-es-rES/strings.xml @@ -138,9 +138,4 @@ Esto puede tardar unos minutos." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-fr/strings.xml b/play-services-core/src/main/res/values-fr/strings.xml index 1fdd82f3..0fcac240 100644 --- a/play-services-core/src/main/res/values-fr/strings.xml +++ b/play-services-core/src/main/res/values-fr/strings.xml @@ -138,9 +138,4 @@ Cela peut prendre quelques minutes." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-he/strings.xml b/play-services-core/src/main/res/values-he/strings.xml index ecd90758..95511eb1 100644 --- a/play-services-core/src/main/res/values-he/strings.xml +++ b/play-services-core/src/main/res/values-he/strings.xml @@ -85,9 +85,4 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-hi/strings.xml b/play-services-core/src/main/res/values-hi/strings.xml index cad50b4c..fdf8ea5a 100644 --- a/play-services-core/src/main/res/values-hi/strings.xml +++ b/play-services-core/src/main/res/values-hi/strings.xml @@ -137,9 +137,4 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-id/strings.xml b/play-services-core/src/main/res/values-id/strings.xml index e00d9da4..ac8b9869 100644 --- a/play-services-core/src/main/res/values-id/strings.xml +++ b/play-services-core/src/main/res/values-id/strings.xml @@ -136,9 +136,4 @@ Ini bisa berlangsung beberapa menit." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-it/strings.xml b/play-services-core/src/main/res/values-it/strings.xml index e73bffc2..07277b42 100755 --- a/play-services-core/src/main/res/values-it/strings.xml +++ b/play-services-core/src/main/res/values-it/strings.xml @@ -135,9 +135,4 @@ Questo potrà richiedere un paio di minuti" Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-ja/strings.xml b/play-services-core/src/main/res/values-ja/strings.xml index 86fad15d..0d93256f 100644 --- a/play-services-core/src/main/res/values-ja/strings.xml +++ b/play-services-core/src/main/res/values-ja/strings.xml @@ -138,9 +138,4 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-ko/strings.xml b/play-services-core/src/main/res/values-ko/strings.xml index 13b7a04f..fa18f6d5 100644 --- a/play-services-core/src/main/res/values-ko/strings.xml +++ b/play-services-core/src/main/res/values-ko/strings.xml @@ -138,9 +138,4 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-lt/strings.xml b/play-services-core/src/main/res/values-lt/strings.xml index ce13b1f3..bdf153d4 100644 --- a/play-services-core/src/main/res/values-lt/strings.xml +++ b/play-services-core/src/main/res/values-lt/strings.xml @@ -138,9 +138,4 @@ Tai gali užtrukti keletą minučių." Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-pt-rBR/strings.xml b/play-services-core/src/main/res/values-pt-rBR/strings.xml index a819d634..1120864e 100644 --- a/play-services-core/src/main/res/values-pt-rBR/strings.xml +++ b/play-services-core/src/main/res/values-pt-rBR/strings.xml @@ -156,9 +156,4 @@ Isso pode demorar alguns minutos." Gerenciar contas do Google conectadas Isso abrirá as configurações do seu dispositivo ! Configurações diversas - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-ru/strings.xml b/play-services-core/src/main/res/values-ru/strings.xml index 00c399e6..61269e80 100644 --- a/play-services-core/src/main/res/values-ru/strings.xml +++ b/play-services-core/src/main/res/values-ru/strings.xml @@ -138,9 +138,4 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-th/strings.xml b/play-services-core/src/main/res/values-th/strings.xml index 2f613b19..3f2df561 100644 --- a/play-services-core/src/main/res/values-th/strings.xml +++ b/play-services-core/src/main/res/values-th/strings.xml @@ -126,9 +126,4 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-tr/strings.xml b/play-services-core/src/main/res/values-tr/strings.xml index 24f96a11..d5f5ddf5 100644 --- a/play-services-core/src/main/res/values-tr/strings.xml +++ b/play-services-core/src/main/res/values-tr/strings.xml @@ -138,9 +138,4 @@ Bunu bilerek yaptıysanız, Google'ın oturum açma sayfasına bağlanmak için Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-uk/strings.xml b/play-services-core/src/main/res/values-uk/strings.xml index 98e3dad5..a63b5a67 100644 --- a/play-services-core/src/main/res/values-uk/strings.xml +++ b/play-services-core/src/main/res/values-uk/strings.xml @@ -138,9 +138,4 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-vi/strings.xml b/play-services-core/src/main/res/values-vi/strings.xml index 33409f1d..df22a69d 100644 --- a/play-services-core/src/main/res/values-vi/strings.xml +++ b/play-services-core/src/main/res/values-vi/strings.xml @@ -141,9 +141,4 @@ Hãy thử lại sau." Quản lý tài khoản Google đã đăng nhập Điều này sẽ mở cài đặt thiết bị của bạn ! Cài đặt khác - Tự động cấp phép đang tắt - Tự động cấp phép đang bật - Tự động cấp phép - Một số ứng dụng có thể yêu cầu xác minh rằng bạn đã mua từ Google Play hay không. Khi ứng dụng đó yêu cầu, Vanced+ microG có thể chứng minh là bạn đã mua ứng dụng đó từ Google Play. Điều này sẽ không áp dụng nếu tùy chọn này được tắt hoặc không có tài khoản Google nào được thêm vào. - Dịch vụ Play diff --git a/play-services-core/src/main/res/values-zh-rCN/strings.xml b/play-services-core/src/main/res/values-zh-rCN/strings.xml index 31bb1f24..5dc520b8 100644 --- a/play-services-core/src/main/res/values-zh-rCN/strings.xml +++ b/play-services-core/src/main/res/values-zh-rCN/strings.xml @@ -137,9 +137,4 @@ Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values-zh-rTW/strings.xml b/play-services-core/src/main/res/values-zh-rTW/strings.xml index 9c80ed44..f4105881 100644 --- a/play-services-core/src/main/res/values-zh-rTW/strings.xml +++ b/play-services-core/src/main/res/values-zh-rTW/strings.xml @@ -145,9 +145,4 @@ Vanced+ microG 會把 Google 帳戶名稱以外的識別位 Manage signed in Google accounts This will open your device settings ! Miscellaneous settings - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. - Play Store services diff --git a/play-services-core/src/main/res/values/strings.xml b/play-services-core/src/main/res/values/strings.xml index c4cd7a0a..236f1198 100755 --- a/play-services-core/src/main/res/values/strings.xml +++ b/play-services-core/src/main/res/values/strings.xml @@ -119,10 +119,7 @@ This can take a couple of minutes." Messages: %1$d (%2$d bytes) Disconnected Connected since %1$s - Licensing off - Licensing on - Answer license verification requests - Some apps require verification that you have purchased them on Google Play. When requested by an app, Vanced+ microG can download a proof of purchase from Google. If disabled, or if no Google account is added, requests for license verification are ignored. + Allow registration Allow the app to register for push notifications. Start app on push message @@ -132,7 +129,7 @@ This can take a couple of minutes." Registered apps Unregistered apps Networks to use for push notifications - Play Store services + Device profile Select profile Native diff --git a/play-services-core/src/main/res/xml/preferences_play.xml b/play-services-core/src/main/res/xml/preferences_play.xml deleted file mode 100644 index df28b60a..00000000 --- a/play-services-core/src/main/res/xml/preferences_play.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/play-services-core/src/main/res/xml/preferences_start.xml b/play-services-core/src/main/res/xml/preferences_start.xml index ae135d57..e7372cee 100755 --- a/play-services-core/src/main/res/xml/preferences_start.xml +++ b/play-services-core/src/main/res/xml/preferences_start.xml @@ -38,11 +38,6 @@ android:title="@string/hideLauncherIcon" android:icon="@drawable/ic_baseline_hide_source_24" android:defaultValue="true"/> - - Date: Sat, 22 Mar 2025 15:54:30 +0700 Subject: [PATCH 27/29] Revert "Add preference for play licensing `microg@4ef2248`" --- .../src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt index fe98a953..e7f83c28 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt @@ -22,7 +22,6 @@ import org.microg.gms.settings.SettingsContract import org.microg.gms.ui.settings.SettingsProvider import org.microg.gms.ui.settings.getAllSettingsProviders import org.microg.tools.ui.ResourceSettingsFragment -import org.microg.gms.play.PlayPreferences import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController @@ -40,10 +39,6 @@ class SettingsFragment : ResourceSettingsFragment() { findNavController().navigate(requireContext(), R.id.openGcmSettings) true } - findPreference(PREF_PLAY)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { - findNavController().navigate(requireContext(), R.id.openPlaySettings) - true - } findPreference(PREF_ABOUT)!!.apply { onPreferenceClickListener = Preference.OnPreferenceClickListener { findNavController().navigate(requireContext(), R.id.openAbout) @@ -113,7 +108,6 @@ class SettingsFragment : ResourceSettingsFragment() { } findPreference(PREF_CHECKIN)?.setSummary(if (CheckinPreferences.isEnabled(context)) R.string.service_status_enabled_short else R.string.service_status_disabled_short) - findPreference(PREF_PLAY)!!.setSummary(if (PlayPreferences.isLicensingEnabled(requireContext())) R.string.pref_play_summary_licensing_on else R.string.pref_play_summary_licensing_off) lifecycleScope.launchWhenResumed { val entries = getAllSettingsProviders(requireContext()).flatMap { it.getEntriesDynamic(requireContext()) } From 843497509c41e6541782bc68095785e41a32cf62 Mon Sep 17 00:00:00 2001 From: cuynu Date: Sat, 22 Mar 2025 16:30:00 +0700 Subject: [PATCH 28/29] add lavender profile --- .../profile_projectinfinityx_redminote7.xml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 play-services-core/src/main/res/xml/profile_projectinfinityx_redminote7.xml diff --git a/play-services-core/src/main/res/xml/profile_projectinfinityx_redminote7.xml b/play-services-core/src/main/res/xml/profile_projectinfinityx_redminote7.xml new file mode 100644 index 00000000..f92014ae --- /dev/null +++ b/play-services-core/src/main/res/xml/profile_projectinfinityx_redminote7.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From e8b5a02903d742aeb168dcd38aec838bc987cf24 Mon Sep 17 00:00:00 2001 From: Cuynu Date: Fri, 1 May 2026 14:46:20 +0700 Subject: [PATCH 29/29] Auth: improve handling of network and timeout exceptions https://github.com/microg/GmsCore/pull/3220 Signed-off-by: Cuynu --- .../org/microg/gms/auth/loginservice/AccountAuthenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/play-services-core/src/main/java/org/microg/gms/auth/loginservice/AccountAuthenticator.java b/play-services-core/src/main/java/org/microg/gms/auth/loginservice/AccountAuthenticator.java index 89ee692f..fa4eb2bc 100644 --- a/play-services-core/src/main/java/org/microg/gms/auth/loginservice/AccountAuthenticator.java +++ b/play-services-core/src/main/java/org/microg/gms/auth/loginservice/AccountAuthenticator.java @@ -104,7 +104,7 @@ class AccountAuthenticator extends AbstractAccountAuthenticator { } } catch (Exception e) { Log.w(TAG, e); - return null; + throw new NetworkErrorException(e); } return null; }