diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml
deleted file mode 100644
index 1913b6f2..00000000
--- a/.github/workflows/debug.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-name: Debug APK Builder
-
-on:
- push:
- branches:
- - master
- pull_request:
- branches:
- - master
-
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v1
- - name: JDK 8 Setup
- uses: actions/setup-java@v1
- with:
- java-version: 11.0.8
-
- - name: Install NDK
- run: echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.0.6113669"
-
- - name: Grant rights
- run: chmod +x ./gradlew
-
- - name: Build project
- run: ./gradlew build
-
- - name: Build APK
- run: ./gradlew assembleDebug
-
- - name: Upload to Artifacts
- uses: actions/upload-artifact@v2
- with:
- name: 'MicroG'
- path: play-services-core/build/outputs/apk/debug/play-services-core-debug.apk
\ No newline at end of file
diff --git a/README.md b/README.md
index b0b2112a..29f47891 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,14 @@
-# Vanced MicroG
+# Vanced+ MicroG
-
-[](https://github.com/inotia00/VancedMicroG/releases) [](https://github.com/inotia00/VancedMicroG/releases)
+This fork tweaks MicroG to be usable by applications that require Google authentication such as [YouTube Vanced+](https://gitlab.com/cuynu/vancedx).
-microG GmsCore is a FLOSS (Free/Libre Open Source Software) framework to allow applications designed for Google Play Services to run on systems, where Play Services is not available.
-
-This fork tweaks MicroG to be usable by applications that require Google authentication such as Vanced.
+## Warning!
+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
- No longer a system app
-- Package name changed from `com.google.android.gms` to `com.mgoogle.android.gms` to support installation alongside the official MicroG
+- Package name changed from `com.google.android.gms` to `com.mgoogle.android.gms` to support installation alongside the official MicroG or device with Google Play Services pre-installed
- Removed unnecessary features:
- Ads
- Analytics
@@ -34,4 +32,4 @@ This fork tweaks MicroG to be usable by applications that require Google authent
## Credits
- Source Code for MicroG 0.2.25.224113 was provided by [@OxrxL](https://github.com/OxrxL)
-- [@shadow578](https://github.com/shadow578)'s commit used to apply ReVanced's `SPOOFED_PACKAGE_SIGNATURE`
\ No newline at end of file
+- [@shadow578](https://github.com/shadow578)'s commit used to apply `SPOOFED_PACKAGE_SIGNATURE`
diff --git a/build.gradle b/build.gradle
index accd8069..bcf0bcbe 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,11 +4,16 @@
*/
buildscript {
- ext.kotlinVersion = '1.7.20'
+ ext.applicationNamespace = "com.google.android.gms"
+ ext.basePackageName = "com.mgoogle"
+
+ ext.safeParcelVersion = '1.7.1'
+
+ ext.kotlinVersion = '1.7.21'
ext.coroutineVersion = '1.6.4'
ext.annotationVersion = '1.5.0'
- ext.appcompatVersion = '1.5.1'
+ ext.appcompatVersion = '1.6.1'
ext.coreVersion = '1.9.0'
ext.collectionVersion = '1.3.0-dev01'
ext.fragmentVersion = '1.5.5'
@@ -20,14 +25,14 @@ buildscript {
ext.circleimageviewVersion = '3.1.0'
ext.volleyVersion = '1.2.1'
- ext.wireVersion = '4.4.3'
+ ext.wireVersion = '4.8.0'
- ext.androidBuildGradleVersion = '7.3.1'
- ext.androidBuildVersionTools = '33.0.1'
+ ext.androidBuildGradleVersion = '8.0.2'
+ ext.androidBuildVersionTools = '33.0.2'
ext.androidMinSdk = 23
- ext.androidTargetSdk = 29
+ ext.androidTargetSdk = 30
ext.androidCompileSdk = 33
repositories {
@@ -42,22 +47,13 @@ buildscript {
}
}
-def execResult(...args) {
- def stdout = new ByteArrayOutputStream()
- exec {
- commandLine args
- standardOutput = stdout
- }
- return stdout.toString()
-}
-def gmsVersion = "22.49.13"
+def gmsVersion = "25.09.34"
def gmsVersionCode = Integer.parseInt(gmsVersion.replaceAll('\\.', ''))
-def ourVersionBase = "0.2.26"
-def ourVersionMinor = 52
+def ourVersionBase = "0.3.0"
-def ourVersionCode = gmsVersionCode * 1000 + ourVersionMinor
+def ourVersionCode = gmsVersionCode * 1000
def ourVersionName = "$ourVersionBase.$gmsVersionCode"
allprojects {
@@ -74,4 +70,13 @@ subprojects {
mavenCentral()
google()
}
+ afterEvaluate {
+ // Temporary hack for Android Studio
+ if (project.plugins.hasPlugin('com.android.base')) {
+ dependencies {
+ compileOnly "org.microg:safe-parcel:$safeParcelVersion"
+ testCompileOnly "org.microg:safe-parcel:$safeParcelVersion"
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/fake-signature/build.gradle b/fake-signature/build.gradle
new file mode 100644
index 00000000..e04d9893
--- /dev/null
+++ b/fake-signature/build.gradle
@@ -0,0 +1,26 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+apply plugin: 'com.android.library'
+
+android {
+ namespace "org.microg.signature.fake"
+
+ compileSdkVersion androidCompileSdk
+ buildToolsVersion androidBuildVersionTools
+
+ defaultConfig {
+ minSdkVersion androidMinSdk
+ targetSdkVersion androidTargetSdk
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
+ }
+}
+
+dependencies {
+}
diff --git a/fake-signature/src/main/AndroidManifest.xml b/fake-signature/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..1b3ae15d
--- /dev/null
+++ b/fake-signature/src/main/AndroidManifest.xml
@@ -0,0 +1,1159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/fake-signature/src/main/res/values/arrays.xml b/fake-signature/src/main/res/values/arrays.xml
new file mode 100644
index 00000000..315cce58
--- /dev/null
+++ b/fake-signature/src/main/res/values/arrays.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ - com.google.android.gms
+ - com.android.vending
+ - com.spotify.music
+
+
+ - com.truecaller
+
+
\ No newline at end of file
diff --git a/play-services-core/src/main/res/values/signature.xml b/fake-signature/src/main/res/values/signature.xml
old mode 100755
new mode 100644
similarity index 56%
rename from play-services-core/src/main/res/values/signature.xml
rename to fake-signature/src/main/res/values/signature.xml
index df53f65c..282e0dc1
--- a/play-services-core/src/main/res/values/signature.xml
+++ b/fake-signature/src/main/res/values/signature.xml
@@ -1,21 +1,14 @@
-
-
+
308204433082032ba003020102020900c2e08746644a308d300d06092a864886f70d01010405003074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f6964301e170d3038303832313233313333345a170d3336303130373233313333345a3074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f696430820120300d06092a864886f70d01010105000382010d00308201080282010100ab562e00d83ba208ae0a966f124e29da11f2ab56d08f58e2cca91303e9b754d372f640a71b1dcb130967624e4656a7776a92193db2e5bfb724a91e77188b0e6a47a43b33d9609b77183145ccdf7b2e586674c9e1565b1f4c6a5955bff251a63dabf9c55c27222252e875e4f8154a645f897168c0b1bfc612eabf785769bb34aa7984dc7e2ea2764cae8307d8c17154d7ee5f64a51a44a602c249054157dc02cd5f5c0e55fbef8519fbe327f0b1511692c5a06f19d18385f5c4dbc2d6b93f68cc2979c70e18ab93866b3bd5db8999552a0e3b4c99df58fb918bedc182ba35e003c1b4b10dd244a8ee24fffd333872ab5221985edab0fc0d0b145b6aa192858e79020103a381d93081d6301d0603551d0e04160414c77d8cc2211756259a7fd382df6be398e4d786a53081a60603551d2304819e30819b8014c77d8cc2211756259a7fd382df6be398e4d786a5a178a4763074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f6964820900c2e08746644a308d300c0603551d13040530030101ff300d06092a864886f70d010104050003820101006dd252ceef85302c360aaace939bcff2cca904bb5d7a1661f8ae46b2994204d0ff4a68c7ed1a531ec4595a623ce60763b167297a7ae35712c407f208f0cb109429124d7b106219c084ca3eb3f9ad5fb871ef92269a8be28bf16d44c8d9a08e6cb2f005bb3fe2cb96447e868e731076ad45b33f6009ea19c161e62641aa99271dfd5228c5c587875ddb7f452758d661f6cc0cccb7352e424cc4365c523532f7325137593c4ae341f4db41edda0d0b1071a7c440f0fe9ea01cb627ca674369d084bd2fd911ff06cdbf2cfa10dc0f893ae35762919048c7efc64c7144178342f70581c9de573af55b390dd7fdb9418631895d5f759f30112687ff621410c069308a
+
+ 308202ed308201d5a003020102020426ffa009300d06092a864886f70d01010b05003027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a656374301e170d3132313030363132303533325a170d3337303933303132303533325a3027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a65637430820122300d06092a864886f70d01010105000382010f003082010a02820101009a8d2a5336b0eaaad89ce447828c7753b157459b79e3215dc962ca48f58c2cd7650df67d2dd7bda0880c682791f32b35c504e43e77b43c3e4e541f86e35a8293a54fb46e6b16af54d3a4eda458f1a7c8bc1b7479861ca7043337180e40079d9cdccb7e051ada9b6c88c9ec635541e2ebf0842521c3024c826f6fd6db6fd117c74e859d5af4db04448965ab5469b71ce719939a06ef30580f50febf96c474a7d265bb63f86a822ff7b643de6b76e966a18553c2858416cf3309dd24278374bdd82b4404ef6f7f122cec93859351fc6e5ea947e3ceb9d67374fe970e593e5cd05c905e1d24f5a5484f4aadef766e498adf64f7cf04bddd602ae8137b6eea40722d0203010001a321301f301d0603551d0e04160414110b7aa9ebc840b20399f69a431f4dba6ac42a64300d06092a864886f70d01010b0500038201010007c32ad893349cf86952fb5a49cfdc9b13f5e3c800aece77b2e7e0e9c83e34052f140f357ec7e6f4b432dc1ed542218a14835acd2df2deea7efd3fd5e8f1c34e1fb39ec6a427c6e6f4178b609b369040ac1f8844b789f3694dc640de06e44b247afed11637173f36f5886170fafd74954049858c6096308fc93c1bc4dd5685fa7a1f982a422f2a3b36baa8c9500474cf2af91c39cbec1bc898d10194d368aa5e91f1137ec115087c31962d8f76cd120d28c249cf76f4c70f5baa08c70a7234ce4123be080cee789477401965cfe537b924ef36747e8caca62dfefdd1a6288dcb1c4fd2aaa6131a7ad254e9742022cfd597d2ca5c660ce9e41ff537e5a4041e37
+
\ No newline at end of file
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.jar b/gradle/wrapper/gradle-wrapper.jar
index 62d4c053..d64cd491 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index d38c612c..0e1ae8ce 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
-#Mon Dec 22 22:27:19 CET 2022
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+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 60cf9e8c..1aa94a42 100755
--- a/gradlew
+++ b/gradlew
@@ -1,6 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: Apache-2.0
#
# Copyright © 2015-2021 the original authors.
#
@@ -56,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -81,13 +80,11 @@ do
esac
done
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-APP_NAME="Gradle"
+# This is normally unused
+# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-
-# 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
@@ -128,26 +125,35 @@ if [ -n "$JAVA_HOME" ] ; then
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
Please set the JAVA_HOME variable in your environment to match the
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.
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=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -192,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" \
@@ -204,6 +214,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
@@ -230,4 +246,4 @@ eval "set -- $(
tr '\n' ' '
)" '"$@"'
-exec "$JAVACMD" "$@"
\ No newline at end of file
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 5093609d..93e3f59f 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +55,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,21 +65,6 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
@@ -86,17 +72,19 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
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-api/src/main/aidl/com/google/android/auth/IAuthManagerService.aidl b/play-services-api/src/main/aidl/com/google/android/auth/IAuthManagerService.aidl
index ae33a334..d6afdf80 100644
--- a/play-services-api/src/main/aidl/com/google/android/auth/IAuthManagerService.aidl
+++ b/play-services-api/src/main/aidl/com/google/android/auth/IAuthManagerService.aidl
@@ -7,7 +7,7 @@ import com.google.android.gms.auth.AccountChangeEventsResponse;
import com.google.android.gms.auth.AccountChangeEventsRequest;
import com.google.android.gms.auth.GetHubTokenRequest;
import com.google.android.gms.auth.GetHubTokenInternalResponse;
-import com.google.android.gms.auth.HasCababilitiesRequest;
+import com.google.android.gms.auth.HasCapabilitiesRequest;
interface IAuthManagerService {
Bundle getToken(String accountName, String scope, in Bundle extras) = 0;
@@ -18,6 +18,6 @@ interface IAuthManagerService {
Bundle getAccounts(in Bundle extras) = 5;
Bundle removeAccount(in Account account) = 6;
Bundle requestGoogleAccountsAccess(String packageName) = 7;
- int hasCapabilities(in HasCababilitiesRequest request) = 8;
+ int hasCapabilities(in HasCapabilitiesRequest request) = 8;
GetHubTokenInternalResponse getHubToken(in GetHubTokenRequest request, in Bundle extras) = 9;
}
diff --git a/play-services-api/src/main/aidl/com/google/android/gms/auth/HasCababilitiesRequest.aidl b/play-services-api/src/main/aidl/com/google/android/gms/auth/HasCapabilitiesRequest.aidl
similarity index 52%
rename from play-services-api/src/main/aidl/com/google/android/gms/auth/HasCababilitiesRequest.aidl
rename to play-services-api/src/main/aidl/com/google/android/gms/auth/HasCapabilitiesRequest.aidl
index c0c080cd..b6cb6b9d 100644
--- a/play-services-api/src/main/aidl/com/google/android/gms/auth/HasCababilitiesRequest.aidl
+++ b/play-services-api/src/main/aidl/com/google/android/gms/auth/HasCapabilitiesRequest.aidl
@@ -1,3 +1,3 @@
package com.google.android.gms.auth;
-parcelable HasCababilitiesRequest;
+parcelable HasCapabilitiesRequest;
diff --git a/play-services-api/src/main/aidl/com/google/android/gms/common/internal/GoogleCertificatesQuery.aidl b/play-services-api/src/main/aidl/com/google/android/gms/common/internal/GoogleCertificatesQuery.aidl
deleted file mode 100644
index ae02e068..00000000
--- a/play-services-api/src/main/aidl/com/google/android/gms/common/internal/GoogleCertificatesQuery.aidl
+++ /dev/null
@@ -1,3 +0,0 @@
-package com.google.android.gms.common.internal;
-
-parcelable GoogleCertificatesQuery;
\ No newline at end of file
diff --git a/play-services-api/src/main/aidl/com/google/android/gms/common/internal/IGoogleCertificatesApi.aidl b/play-services-api/src/main/aidl/com/google/android/gms/common/internal/IGoogleCertificatesApi.aidl
deleted file mode 100644
index da539f32..00000000
--- a/play-services-api/src/main/aidl/com/google/android/gms/common/internal/IGoogleCertificatesApi.aidl
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.google.android.gms.common.internal;
-
-import com.google.android.gms.common.internal.GoogleCertificatesQuery;
-import com.google.android.gms.dynamic.IObjectWrapper;
-
-interface IGoogleCertificatesApi {
- IObjectWrapper getGoogleCertficates();
- IObjectWrapper getGoogleReleaseCertificates();
- boolean isGoogleReleaseSigned(String packageName, IObjectWrapper certData);
- boolean isGoogleSigned(String packageName, IObjectWrapper certData);
- boolean isGoogleOrPlatformSigned(in GoogleCertificatesQuery query, IObjectWrapper packageManager);
-}
\ No newline at end of file
diff --git a/play-services-api/src/main/java/com/google/android/gms/auth/HasCababilitiesRequest.java b/play-services-api/src/main/java/com/google/android/gms/auth/HasCapabilitiesRequest.java
similarity index 63%
rename from play-services-api/src/main/java/com/google/android/gms/auth/HasCababilitiesRequest.java
rename to play-services-api/src/main/java/com/google/android/gms/auth/HasCapabilitiesRequest.java
index 27b94732..e35ca6d7 100644
--- a/play-services-api/src/main/java/com/google/android/gms/auth/HasCababilitiesRequest.java
+++ b/play-services-api/src/main/java/com/google/android/gms/auth/HasCapabilitiesRequest.java
@@ -9,10 +9,10 @@ import android.accounts.Account;
import org.microg.safeparcel.AutoSafeParcelable;
-public class HasCababilitiesRequest extends AutoSafeParcelable {
+public class HasCapabilitiesRequest extends AutoSafeParcelable {
@Field(1)
public Account account;
@Field(2)
public String[] capabilities;
- public static final Creator CREATOR = new AutoCreator<>(HasCababilitiesRequest.class);
+ public static final Creator CREATOR = new AutoCreator<>(HasCapabilitiesRequest.class);
}
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-api/src/main/java/com/google/android/gms/common/data/DataHolder.java b/play-services-base-api/src/main/java/com/google/android/gms/common/data/DataHolder.java
index f7b8e46a..4af2bcf1 100644
--- a/play-services-base-api/src/main/java/com/google/android/gms/common/data/DataHolder.java
+++ b/play-services-base-api/src/main/java/com/google/android/gms/common/data/DataHolder.java
@@ -18,8 +18,12 @@ package com.google.android.gms.common.data;
import android.annotation.SuppressLint;
import android.content.ContentValues;
+import android.database.AbstractWindowedCursor;
+import android.database.CharArrayBuffer;
import android.database.Cursor;
import android.database.CursorWindow;
+import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
@@ -41,6 +45,9 @@ import java.util.Map;
*/
@PublicApi(until = "1")
public class DataHolder extends AutoSafeParcelable implements Closeable {
+ @SafeParceled(1000)
+ private final int versionCode = 1;
+
@SafeParceled(1)
private final String[] columns;
@@ -62,6 +69,13 @@ public class DataHolder extends AutoSafeParcelable implements Closeable {
protected static final int FIELD_TYPE_STRING = 3;
protected static final int FIELD_TYPE_BLOB = 4;
+ private DataHolder() {
+ columns = null;
+ windows = null;
+ statusCode = 0;
+ metadata = null;
+ }
+
/**
* Creates a data holder with the specified data.
*
@@ -78,6 +92,17 @@ public class DataHolder extends AutoSafeParcelable implements Closeable {
validateContents();
}
+ /**
+ * Creates a data holder wrapping the provided cursor, with provided status code and metadata.
+ *
+ * @param cursor The cursor containing the data.
+ * @param statusCode The status code of this {@link DataHolder}.
+ * @param metadata The metadata associated with this {@link DataHolder} (may be null).
+ */
+ public DataHolder(AbstractWindowedCursor cursor, int statusCode, Bundle metadata) {
+ this(cursor.getColumnNames(), createCursorWindows(cursor), statusCode, metadata);
+ }
+
/**
* Creates a data holder wrapping the provided cursor, with provided status code and metadata.
*
@@ -110,7 +135,23 @@ public class DataHolder extends AutoSafeParcelable implements Closeable {
return builder(columns, null);
}
- @SuppressWarnings("deprecation")
+ /**
+ * @param statusCode The status code of this {@link DataHolder}.
+ * @param metadata The metadata associated with this {@link DataHolder} (may be null).
+ * @return An empty {@link DataHolder} object with the given status and metadata.
+ */
+ public static DataHolder empty(int statusCode, Bundle metadata) {
+ return new DataHolder(new String[0], new CursorWindow[0], statusCode, metadata);
+ }
+
+ /**
+ * @param statusCode The status code of this {@link DataHolder}.
+ * @return An empty {@link DataHolder} object with the given status and null metadata.
+ */
+ public static DataHolder empty(int statusCode) {
+ return empty(statusCode, null);
+ }
+
@SuppressLint({"NewApi", "ObsoleteSdkInt"})
static int getCursorType(Cursor cursor, int i) {
return cursor.getType(i);
@@ -131,6 +172,20 @@ public class DataHolder extends AutoSafeParcelable implements Closeable {
}
}
+ /**
+ * Copies the String content in the given column at the provided position into a {@link CharArrayBuffer}.
+ * This will throw an {@link IllegalArgumentException} if the column does not exist, the
+ * position is invalid, or the data holder has been closed.
+ *
+ * @param column The column to retrieve.
+ * @param row The row to retrieve the data from.
+ * @param windowIndex Index of the cursor window to extract the data from.
+ * @param dataOut The {@link CharArrayBuffer} to copy into.
+ */
+ public void copyToBuffer(String column, int row, int windowIndex, CharArrayBuffer dataOut) {
+ throw new RuntimeException("Not yet available");
+ }
+
@SuppressWarnings("deprecation")
private static CursorWindow[] createCursorWindows(Builder builder) {
if (builder.columns.length == 0) return new CursorWindow[0];
@@ -223,6 +278,34 @@ public class DataHolder extends AutoSafeParcelable implements Closeable {
return windows.toArray(new CursorWindow[0]);
}
+ /**
+ * Retrieves the boolean value for a given column at the provided position.
+ * This will throw an {@link IllegalArgumentException} if the column does not exist, the
+ * position is invalid, or the data holder has been closed.
+ *
+ * @param column The column to retrieve.
+ * @param row The row to retrieve the data from.
+ * @param windowIndex Index of the cursor window to extract the data from.
+ * @return The boolean value in that column.
+ */
+ public boolean getBoolean(String column, int row, int windowIndex) {
+ return windows[windowIndex].getLong(row, columnIndices.get(column)) == 1;
+ }
+
+ /**
+ * Retrieves the byte array value for a given column at the provided position.
+ * This will throw an {@link IllegalArgumentException} if the column does not exist, the
+ * position is invalid, or the data holder has been closed.
+ *
+ * @param column The column to retrieve.
+ * @param row The row to retrieve the data from.
+ * @param windowIndex Index of the cursor window to extract the data from.
+ * @return The byte array value in that column.
+ */
+ public byte[] getByteArray(String column, int row, int windowIndex) {
+ return windows[windowIndex].getBlob(row, columnIndices.get(column));
+ }
+
/**
* Gets the number of rows in the data holder.
*
@@ -238,6 +321,38 @@ public class DataHolder extends AutoSafeParcelable implements Closeable {
return c;
}
+ /**
+ * Retrieves the integer value for a given column at the provided position.
+ * This will throw an {@link IllegalArgumentException} if the column does not exist, the
+ * position is invalid, or the data holder has been closed.
+ *
+ * @param column The column to retrieve.
+ * @param row The row to retrieve the data from.
+ * @param windowIndex Index of the cursor window to extract the data from.
+ * @return The integer value in that column.
+ */
+ public int getInteger(String column, int row, int windowIndex) {
+ return windows[windowIndex].getInt(row, columnIndices.get(column));
+ }
+
+ /**
+ * Retrieves the long value for a given column at the provided position.
+ * This will throw an {@link IllegalArgumentException} if the column does not exist, the
+ * position is invalid, or the data holder has been closed.
+ *
+ * @param column The column to retrieve.
+ * @param row The row to retrieve the data from.
+ * @param windowIndex Index of the cursor window to extract the data from.
+ * @return The long value in that column.
+ */
+ public long getLong(String column, int row, int windowIndex) {
+ return windows[windowIndex].getLong(row, columnIndices.get(column));
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
/**
* Retrieves the string value for a given column at the provided position.
* This will throw an {@link IllegalArgumentException} if the column does not exist, the
@@ -252,6 +367,42 @@ public class DataHolder extends AutoSafeParcelable implements Closeable {
return windows[windowIndex].getString(row, columnIndices.get(column));
}
+ /**
+ * Returns whether the given column at the provided position contains null.
+ * This will throw an {@link IllegalArgumentException} if the column does not exist, the
+ * position is invalid, or the data holder has been closed.
+ *
+ * @param column The column to retrieve.
+ * @param row The row to retrieve the data from.
+ * @param windowIndex Index of the cursor window to extract the data from.
+ * @return Whether the column value is null at this position.
+ */
+ public boolean isNull(String column, int row, int windowIndex) {
+ return windows[windowIndex].isNull(row, columnIndices.get(column));
+ }
+
+ public boolean isClosed() {
+ synchronized (this) {
+ return closed;
+ }
+ }
+
+ /**
+ * Retrieves the column data at the provided position as a URI if possible, checking for null values.
+ * This will throw an {@link IllegalArgumentException} if the column does not exist, the
+ * position is invalid, or the data holder has been closed.
+ *
+ * @param column The column to retrieve.
+ * @param row The row to retrieve the data from.
+ * @param windowIndex Index of the cursor window to extract the data from.
+ * @return The column data as a URI, or null if not present.
+ */
+ public Uri parseUri(String column, int row, int windowIndex) {
+ String string = getString(column, row, windowIndex);
+ if (string != null) return Uri.parse(string);
+ return null;
+ }
+
@Override
public String toString() {
return "DataHolder{" +
@@ -315,6 +466,18 @@ public class DataHolder extends AutoSafeParcelable implements Closeable {
return rows.size();
}
+ /**
+ * Sort the rows in this builder based on the standard data type comparisons for the value in the provided column.
+ * Calling this multiple times with the same column will not change the sort order of the builder.
+ * Note that any data which is added after this call will not be sorted.
+ *
+ * @param sortColumn The column to sort the rows in this builder by.
+ * @return {@link DataHolder.Builder} to continue construction.
+ */
+ public Builder sort(String sortColumn) {
+ throw new RuntimeException("Not yet implemented");
+ }
+
/**
* Add a new row of data to the {@link DataHolder} this {@link DataHolder.Builder} will create. Note that the data must contain an entry for all columns
*
diff --git a/play-services-base-core/build.gradle b/play-services-base-core/build.gradle
index a0849ff8..34288f21 100644
--- a/play-services-base-core/build.gradle
+++ b/play-services-base-core/build.gradle
@@ -21,9 +21,10 @@ android {
buildToolsVersion androidBuildVersionTools
defaultConfig {
- versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
+
+ buildConfigField "String", "BASE_PACKAGE_NAME", "\"$basePackageName\""
}
sourceSets {
@@ -31,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 de583c4d..369707e7 100644
--- a/play-services-base-core/src/main/AndroidManifest.xml
+++ b/play-services-base-core/src/main/AndroidManifest.xml
@@ -3,11 +3,26 @@
~ SPDX-FileCopyrightText: 2020, microG Project Team
~ SPDX-License-Identifier: Apache-2.0
-->
-
+
+
+
+
+
+ android:exported="true"
+ android:readPermission="${applicationId}.permission.READ_SETTINGS"
+ android:writePermission="${applicationId}.permission.WRITE_SETTINGS" />
+
+
diff --git a/play-services-base-core/src/main/java/org/microg/gms/AbstractGmsServiceBroker.java b/play-services-base-core/src/main/java/org/microg/gms/AbstractGmsServiceBroker.java
index 1cd39310..a0ff2b99 100644
--- a/play-services-base-core/src/main/java/org/microg/gms/AbstractGmsServiceBroker.java
+++ b/play-services-base-core/src/main/java/org/microg/gms/AbstractGmsServiceBroker.java
@@ -18,7 +18,6 @@ package org.microg.gms;
import android.accounts.Account;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
@@ -29,6 +28,7 @@ import com.google.android.gms.common.internal.IGmsCallbacks;
import com.google.android.gms.common.internal.IGmsServiceBroker;
import com.google.android.gms.common.internal.ValidateAccountRequest;
+import org.microg.gms.base.core.BuildConfig;
import org.microg.gms.common.GmsService;
import java.util.EnumSet;
@@ -77,7 +77,7 @@ public abstract class AbstractGmsServiceBroker extends IGmsServiceBroker.Stub {
request.gmsVersion = gmsVersion;
request.packageName = packageName;
request.extras = extras;
- request.account = accountName == null ? null : new Account(accountName, "com.mgoogle");
+ request.account = accountName == null ? null : new Account(accountName, BuildConfig.BASE_PACKAGE_NAME);
request.scopes = scopes == null ? null : scopesFromStringArray(scopes);
getService(callback, request);
}
diff --git a/play-services-base-core/src/main/java/org/microg/gms/common/DeviceConfiguration.java b/play-services-base-core/src/main/java/org/microg/gms/common/DeviceConfiguration.java
index d4ab5940..55bffb3c 100644
--- a/play-services-base-core/src/main/java/org/microg/gms/common/DeviceConfiguration.java
+++ b/play-services-base-core/src/main/java/org/microg/gms/common/DeviceConfiguration.java
@@ -16,6 +16,8 @@
package org.microg.gms.common;
+import android.annotation.SuppressLint;
+
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
@@ -26,6 +28,8 @@ import android.opengl.GLES10;
import android.os.Build;
import android.util.DisplayMetrics;
+import org.microg.gms.profile.ProfileManager;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -56,6 +60,7 @@ public class DeviceConfiguration {
public int widthPixels;
public DeviceConfiguration(Context context) {
+ ProfileManager.ensureInitialized(context);
ConfigurationInfo configurationInfo = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getDeviceConfigurationInfo();
touchScreen = configurationInfo.reqTouchScreen;
keyboardType = configurationInfo.reqKeyboardType;
@@ -78,29 +83,35 @@ public class DeviceConfiguration {
}
Collections.sort(sharedLibraries);
availableFeatures = new ArrayList<>();
- if (packageManager.getSystemAvailableFeatures() != null) {
- for (FeatureInfo featureInfo : packageManager.getSystemAvailableFeatures()) {
- if (featureInfo != null && featureInfo.name != null) availableFeatures.add(featureInfo.name);
- }
+ packageManager.getSystemAvailableFeatures();
+ for (FeatureInfo featureInfo : packageManager.getSystemAvailableFeatures()) {
+ if (featureInfo != null && featureInfo.name != null)
+ availableFeatures.add(featureInfo.name);
}
Collections.sort(availableFeatures);
this.nativePlatforms = getNativePlatforms();
widthPixels = displayMetrics.widthPixels;
heightPixels = displayMetrics.heightPixels;
- locales = new ArrayList<>(Arrays.asList(context.getAssets().getLocales()));
- for (int i = 0; i < locales.size(); i++) {
- locales.set(i, locales.get(i).replace("-", "_"));
- }
- Collections.sort(locales);
+ locales = getLocales(context);
Set glExtensions = new HashSet<>();
addEglExtensions(glExtensions);
this.glExtensions = new ArrayList<>(glExtensions);
Collections.sort(this.glExtensions);
}
- @SuppressWarnings({"deprecation", "InlinedApi"})
+ @SuppressLint("GetLocales")
+ private static List getLocales(Context context) {
+ List locales = new ArrayList();
+ locales.addAll(Arrays.asList(context.getAssets().getLocales()));
+ for (int i = 0; i < locales.size(); i++) {
+ locales.set(i, locales.get(i).replace("-", "_"));
+ }
+ Collections.sort(locales);
+ return locales;
+ }
+
+ @SuppressWarnings({"InlinedApi"})
private static List getNativePlatforms() {
- List nativePlatforms;
return Arrays.asList(Build.SUPPORTED_ABIS);
}
diff --git a/play-services-base-core/src/main/java/org/microg/gms/common/ForegroundServiceContext.java b/play-services-base-core/src/main/java/org/microg/gms/common/ForegroundServiceContext.java
index c7a2ff52..417ad6f7 100644
--- a/play-services-base-core/src/main/java/org/microg/gms/common/ForegroundServiceContext.java
+++ b/play-services-base-core/src/main/java/org/microg/gms/common/ForegroundServiceContext.java
@@ -1,5 +1,7 @@
package org.microg.gms.common;
+import static android.os.Build.VERSION.SDK_INT;
+
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -11,7 +13,6 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.net.Uri;
-import android.os.Build;
import android.os.PowerManager;
import android.provider.Settings;
import android.util.Log;
@@ -33,7 +34,7 @@ public class ForegroundServiceContext extends ContextWrapper {
if (!isIgnoringBatteryOptimizations()) {
Log.d(TAG, "Starting in foreground mode.");
service.putExtra(EXTRA_FOREGROUND, true);
- if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ if (SDK_INT >= 26) {
return super.startForegroundService(service);
} else {
return super.startService(service);
@@ -75,7 +76,7 @@ public class ForegroundServiceContext extends ContextWrapper {
String serviceName = getServiceName(service);
Log.d(tag, "Started " + serviceName + " in foreground mode.");
try {
- Notification notification = buildForegroundNotification(service, serviceName);
+ Notification notification = buildForegroundNotification(service);
service.startForeground(serviceName.hashCode(), notification);
Log.d(tag, "Notification: " + notification);
} catch (Exception e) {
@@ -85,9 +86,9 @@ public class ForegroundServiceContext extends ContextWrapper {
}
@SuppressLint("BatteryLife")
- private static Notification buildForegroundNotification(Context context, String serviceName) {
+ private static Notification buildForegroundNotification(Context context) {
Intent notificationIntent = new Intent();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ if (SDK_INT >= 31) {
notificationIntent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
notificationIntent.setData(Uri.parse("package:" + context.getPackageName()));
} else {
@@ -97,8 +98,8 @@ public class ForegroundServiceContext extends ContextWrapper {
PendingIntent notificationPendingIntent = PendingIntent.getActivity(context,
0,
notificationIntent,
- 0);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ PendingIntent.FLAG_IMMUTABLE);
+ if (SDK_INT >= 26) {
NotificationChannel Channel = new NotificationChannel("foreground-service",
context.getResources().getString(R.string.notification_service_name),
NotificationManager.IMPORTANCE_LOW);
diff --git a/play-services-base-core/src/main/java/org/microg/gms/common/PackageUtils.java b/play-services-base-core/src/main/java/org/microg/gms/common/PackageUtils.java
index 50d112d0..03fd8b93 100644
--- a/play-services-base-core/src/main/java/org/microg/gms/common/PackageUtils.java
+++ b/play-services-base-core/src/main/java/org/microg/gms/common/PackageUtils.java
@@ -16,6 +16,10 @@
package org.microg.gms.common;
+import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
+import static org.microg.gms.common.Constants.GMS_PACKAGE_SIGNATURE_SHA1;
+
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.Application;
import android.app.PendingIntent;
@@ -28,6 +32,8 @@ import android.util.Log;
import androidx.annotation.Nullable;
+import org.microg.gms.base.core.BuildConfig;
+
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -35,28 +41,25 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-
-import static android.os.Build.VERSION.SDK_INT;
-import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
-import static org.microg.gms.common.Constants.GMS_PACKAGE_SIGNATURE_SHA1;
-import static org.microg.gms.common.Constants.GMS_SECONDARY_PACKAGE_SIGNATURE_SHA1;
+import java.util.Objects;
public class PackageUtils {
private static final String GOOGLE_PLATFORM_KEY = GMS_PACKAGE_SIGNATURE_SHA1;
- private static final String GOOGLE_PLATFORM_KEY_2 = GMS_SECONDARY_PACKAGE_SIGNATURE_SHA1;
- private static final String GOOGLE_APP_KEY = "24bb24c05e47e0aefa68a58a766179d9b613a600";
- private static final String[] GOOGLE_PRIMARY_KEYS = {GOOGLE_PLATFORM_KEY, GOOGLE_PLATFORM_KEY_2, GOOGLE_APP_KEY};
+ private static final String GOOGLE_LEGACY_KEY = "58e1c4133f7441ec3d2c270270a14802da47ba0e"; // Seems to be no longer used.
+ private static final String[] GOOGLE_PRIMARY_KEYS = {GOOGLE_PLATFORM_KEY, "24bb24c05e47e0aefa68a58a766179d9b613a600", "afb0fed5eeaebdd86f56a97742f4b6b33ef59875", "61226bdb57cc32c8a2a9ef71f7bc9548e95dcc0b", "3a82b5ee26bc46bf68113d920e610cd090198d4a"};
- private static final Map KNOWN_GOOGLE_PACKAGES;
+ public static final Map KNOWN_GOOGLE_PACKAGES;
static {
KNOWN_GOOGLE_PACKAGES = new HashMap<>();
+ KNOWN_GOOGLE_PACKAGES.put("com.google.android.apps.youtube", "24bb24c05e47e0aefa68a58a766179d9b613a600");
KNOWN_GOOGLE_PACKAGES.put("com.google.android.apps.youtube.music", "afb0fed5eeaebdd86f56a97742f4b6b33ef59875");
}
public static boolean isGooglePackage(Context context, String packageName) {
String signatureDigest = firstSignatureDigest(context, packageName);
+ packageName = PackageSpoofUtils.spoofPackageName(context.getPackageManager(), packageName);
return isGooglePackage(packageName, signatureDigest);
}
@@ -73,7 +76,7 @@ public class PackageUtils {
if (signatureDigest == null) return false;
if (Arrays.asList(GOOGLE_PRIMARY_KEYS).contains(signatureDigest)) return true;
if (!KNOWN_GOOGLE_PACKAGES.containsKey(packageName)) return false;
- return KNOWN_GOOGLE_PACKAGES.get(packageName).equals(signatureDigest);
+ return Objects.equals(KNOWN_GOOGLE_PACKAGES.get(packageName), signatureDigest);
}
public static void assertExtendedAccess(Context context) {
@@ -83,14 +86,14 @@ public class PackageUtils {
public static boolean callerHasExtendedAccess(Context context) {
String[] packagesForUid = context.getPackageManager().getPackagesForUid(Binder.getCallingUid());
- if (packagesForUid != null && packagesForUid.length != 0) {
+ if (packagesForUid != null) {
for (String packageName : packagesForUid) {
packageName = PackageSpoofUtils.spoofPackageName(context.getPackageManager(), packageName);
if (isGooglePackage(context, packageName) || GMS_PACKAGE_NAME.equals(packageName))
return true;
}
}
- return context.checkCallingPermission("org.mgoogle.gms.EXTENDED_ACCESS") == PackageManager.PERMISSION_GRANTED;
+ return context.checkCallingPermission(BuildConfig.BASE_PACKAGE_NAME + ".gms.EXTENDED_ACCESS") == PackageManager.PERMISSION_GRANTED;
}
public static void checkPackageUid(Context context, String packageName, int callingUid) {
@@ -120,9 +123,9 @@ public class PackageUtils {
try {
info = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
} catch (PackageManager.NameNotFoundException e) {
- return null;
+ return KNOWN_GOOGLE_PACKAGES.get(packageName);
}
- if (info != null && info.signatures != null && info.signatures.length > 0) {
+ if (info != null && info.signatures != null) {
for (Signature sig : info.signatures) {
String digest = sha1sum(sig.toByteArray());
if (digest != null) {
@@ -147,7 +150,7 @@ public class PackageUtils {
} catch (PackageManager.NameNotFoundException e) {
return null;
}
- if (info != null && info.signatures != null && info.signatures.length > 0) {
+ if (info != null && info.signatures != null) {
for (Signature sig : info.signatures) {
byte[] digest = sha1bytes(sig.toByteArray());
if (digest != null) {
@@ -178,10 +181,7 @@ public class PackageUtils {
} catch (final NoSuchAlgorithmException e) {
return null;
}
- if (md != null) {
- return md.digest(bytes);
- }
- return null;
+ return md.digest(bytes);
}
@Nullable
@@ -220,7 +220,7 @@ public class PackageUtils {
if (suggestedCallerPid > 0 && suggestedCallerPid != callingPid) {
throw new SecurityException("suggested PID [" + suggestedCallerPid + "] and real calling PID [" + callingPid + "] mismatch!");
}
- return getAndCheckPackage(context, suggestedPackageName, callingUid, Binder.getCallingPid());
+ return getAndCheckPackage(context, suggestedPackageName, callingUid, callingPid);
}
@Nullable
@@ -252,7 +252,6 @@ public class PackageUtils {
}
@Nullable
- @Deprecated
public static String packageFromProcessId(Context context, int pid) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (manager == null) return null;
@@ -277,7 +276,6 @@ public class PackageUtils {
return null;
}
- @SuppressWarnings("deprecation")
public static String packageFromPendingIntent(PendingIntent pi) {
if (pi == null) return null;
return pi.getCreatorPackage();
@@ -287,8 +285,10 @@ public class PackageUtils {
if (android.os.Build.VERSION.SDK_INT >= 28)
return Application.getProcessName();
try {
+ @SuppressLint("PrivateApi")
Class> activityThread = Class.forName("android.app.ActivityThread");
String methodName = "currentProcessName";
+ @SuppressLint("DiscouragedPrivateApi")
Method getProcessName = activityThread.getDeclaredMethod(methodName);
return (String) getProcessName.invoke(null);
} catch (Exception e) {
@@ -333,17 +333,12 @@ public class PackageUtils {
} catch (final NoSuchAlgorithmException e) {
return null;
}
- if (md != null) {
- bytes = md.digest(bytes);
- if (bytes != null) {
- StringBuilder sb = new StringBuilder(2 * bytes.length);
- for (byte b : bytes) {
- sb.append(String.format("%02x", b));
- }
- return sb.toString();
- }
+ bytes = md.digest(bytes);
+ StringBuilder sb = new StringBuilder(2 * bytes.length);
+ for (byte b : bytes) {
+ sb.append(String.format("%02x", b));
}
- return null;
+ return sb.toString();
}
public static int versionCode(Context context, String packageName) {
diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/common/PackageSpoofUtils.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/common/PackageSpoofUtils.kt
index 94ec088d..7aec1077 100644
--- a/play-services-base-core/src/main/kotlin/org/microg/gms/common/PackageSpoofUtils.kt
+++ b/play-services-base-core/src/main/kotlin/org/microg/gms/common/PackageSpoofUtils.kt
@@ -4,15 +4,17 @@ import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
+import org.microg.gms.base.core.BuildConfig
+
/**
* utilities to spoof package information
*/
internal object PackageSpoofUtils {
private const val TAG = "SpoofUtils"
private const val META_SPOOF_PACKAGE_NAME =
- "com.mgoogle.android.gms.SPOOFED_PACKAGE_NAME"
+ "${BuildConfig.BASE_PACKAGE_NAME}.android.gms.SPOOFED_PACKAGE_NAME"
private const val META_SPOOF_PACKAGE_SIGNATURE =
- "com.mgoogle.android.gms.SPOOFED_PACKAGE_SIGNATURE"
+ "${BuildConfig.BASE_PACKAGE_NAME}.android.gms.SPOOFED_PACKAGE_SIGNATURE"
private val spoofedPackageNameCache = HashMap()
private val spoofedPackageSignatureCache = HashMap()
@@ -139,6 +141,7 @@ internal object PackageSpoofUtils {
* @param packageName name of the package to get metadata of
* @return package metadata bundle
*/
+ @Suppress("DEPRECATION")
private fun getPackageMetadata(packageManager: PackageManager, packageName: String): Bundle? {
return try {
// PackageManager.getPackageInfo() has been deprecated in targetSdkVersion 30+
diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/profile/Build.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/profile/Build.kt
index a52059a9..725e0d6a 100644
--- a/play-services-base-core/src/main/kotlin/org/microg/gms/profile/Build.kt
+++ b/play-services-base-core/src/main/kotlin/org/microg/gms/profile/Build.kt
@@ -24,7 +24,6 @@ object Build {
var CPU_ABI2: String? = null
@JvmField
- @TargetApi(21)
var SUPPORTED_ABIS: Array = emptyArray()
@JvmField
@@ -90,6 +89,9 @@ object Build {
@JvmField
var SECURITY_PATCH: String? = null
+
+ @JvmField
+ var DEVICE_INITIAL_SDK_INT: Int = 0
}
fun generateWebViewUserAgentString(original: String): String {
diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt
index ed756017..76286eab 100644
--- a/play-services-base-core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt
+++ b/play-services-base-core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt
@@ -10,8 +10,8 @@ import android.content.Context
import android.content.res.XmlResourceParser
import android.util.Log
import org.microg.gms.utils.FileXmlResourceParser
-import org.microg.mgms.settings.SettingsContract
-import org.microg.mgms.settings.SettingsContract.Profile
+import org.microg.gms.settings.SettingsContract
+import org.microg.gms.settings.SettingsContract.Profile
import org.xmlpull.v1.XmlPullParser
import java.io.File
import java.util.*
@@ -68,43 +68,60 @@ object ProfileManager {
PROFILE_AUTO -> false
PROFILE_REAL -> false
PROFILE_NATIVE -> true
- else -> getProfileXml(context, profile)?.use {
- var next = it.next()
- while (next != XmlPullParser.END_DOCUMENT) {
- when (next) {
- XmlPullParser.START_TAG -> when (it.name) {
- "profile" -> {
- return@use it.getAttributeBooleanValue(null, "auto", false)
+ else -> {
+ val parser = getProfileXml(context, profile)
+ if (parser != null) {
+ try {
+ var next = parser.next()
+ while (next != XmlPullParser.END_DOCUMENT) {
+ when (next) {
+ XmlPullParser.START_TAG -> when (parser.name) {
+ "profile" -> {
+ return@runCatching parser.getAttributeBooleanValue(null, "auto", false)
+ }
+ }
}
+ next = parser.next()
}
+ } finally {
+ parser.close()
}
- next = it.next()
+ false
+ } else {
+ false
}
- } == true
+ }
}
}.getOrDefault(false)
+ fun getActiveProfileData(context: Context): Map =
+ getProfileData(context, getProfile(context), getRealData())
+
private fun getProfileData(context: Context, profile: String, realData: Map): Map {
try {
if (profile in listOf(PROFILE_REAL, PROFILE_NATIVE)) return realData
- val profileResId = getProfileResId(context, profile)
- if (profileResId == 0) return realData
+ if (profile != PROFILE_USER && getProfileResId(context, profile) == 0) return realData
val resultData = mutableMapOf()
resultData.putAll(realData)
- getProfileXml(context, profile)?.use {
- var next = it.next()
- while (next != XmlPullParser.END_DOCUMENT) {
- when (next) {
- XmlPullParser.START_TAG -> when (it.name) {
- "data" -> {
- val key = it.getAttributeValue(null, "key")
- val value = it.getAttributeValue(null, "value")
- resultData[key] = value
- Log.d(TAG, "Overwrite from profile: $key = $value")
+ val parser = getProfileXml(context, profile)
+ if (parser != null) {
+ try {
+ var next = parser.next()
+ while (next != XmlPullParser.END_DOCUMENT) {
+ when (next) {
+ XmlPullParser.START_TAG -> when (parser.name) {
+ "data" -> {
+ val key = parser.getAttributeValue(null, "key")
+ val value = parser.getAttributeValue(null, "value")
+ resultData[key] = value
+ Log.d(TAG, "Overwrite from profile: $key = $value")
+ }
}
}
+ next = parser.next()
}
- next = it.next()
+ } finally {
+ parser.close()
}
}
return resultData
@@ -152,15 +169,20 @@ object ProfileManager {
// From profile
try {
- getProfileXml(context, profile)?.use {
- var next = it.next()
- while (next != XmlPullParser.END_DOCUMENT) {
- when (next) {
- XmlPullParser.START_TAG -> when (it.name) {
- "serial" -> return it.getAttributeValue(null, "template")
+ val parser = getProfileXml(context, profile)
+ if (parser != null) {
+ try {
+ var next = parser.next()
+ while (next != XmlPullParser.END_DOCUMENT) {
+ when (next) {
+ XmlPullParser.START_TAG -> when (parser.name) {
+ "serial" -> return parser.getAttributeValue(null, "template")
+ }
}
+ next = parser.next()
}
- next = it.next()
+ } finally {
+ parser.close()
}
}
} catch (e: Exception) {
@@ -183,6 +205,7 @@ object ProfileManager {
return serial
}
+ @SuppressLint("BlockedPrivateApi")
private fun getRealData(): Map = mutableMapOf(
"Build.BOARD" to android.os.Build.BOARD,
"Build.BOOTLOADER" to android.os.Build.BOOTLOADER,
@@ -216,9 +239,15 @@ object ProfileManager {
if (android.os.Build.VERSION.SDK_INT >= 23) {
put("Build.VERSION.SECURITY_PATCH", android.os.Build.VERSION.SECURITY_PATCH)
}
+ try {
+ val field = android.os.Build.VERSION::class.java.getDeclaredField("DEVICE_INITIAL_SDK_INT")
+ field.isAccessible = true
+ put("Build.VERSION.DEVICE_INITIAL_SDK_INT", field.getInt(null).toString())
+ } catch (ignored: Exception) {
+ }
}
- private fun applyProfileData(profileData: Map) {
+ fun applyProfileData(profileData: Map) {
fun applyStringField(key: String, valueSetter: (String) -> Unit) = profileData[key]?.let { valueSetter(it) }
fun applyIntField(key: String, valueSetter: (Int) -> Unit) = profileData[key]?.toIntOrNull()?.let { valueSetter(it) }
fun applyLongField(key: String, valueSetter: (Long) -> Unit) = profileData[key]?.toLongOrNull()?.let { valueSetter(it) }
@@ -248,6 +277,7 @@ object ProfileManager {
applyStringField("Build.VERSION.RELEASE") { Build.VERSION.RELEASE = it }
applyStringField("Build.VERSION.SDK") { Build.VERSION.SDK = it }
applyIntField("Build.VERSION.SDK_INT") { Build.VERSION.SDK_INT = it }
+ applyIntField("Build.VERSION.DEVICE_INITIAL_SDK_INT") { Build.VERSION.DEVICE_INITIAL_SDK_INT = it }
if (android.os.Build.VERSION.SDK_INT >= 21) {
Build.SUPPORTED_ABIS = profileData["Build.SUPPORTED_ABIS"]?.split(",")?.toTypedArray() ?: emptyArray()
} else {
@@ -275,19 +305,26 @@ object ProfileManager {
fun getProfileName(context: Context, profile: String): String? = getProfileName { getProfileXml(context, profile) }
- private fun getProfileName(parserCreator: () -> XmlResourceParser?): String? = parserCreator()?.use {
- var next = it.next()
- while (next != XmlPullParser.END_DOCUMENT) {
- when (next) {
- XmlPullParser.START_TAG -> when (it.name) {
- "profile" -> {
- return@use it.getAttributeValue(null, "name")
+ private fun getProfileName(parserCreator: () -> XmlResourceParser?): String? {
+ val parser = parserCreator()
+ if (parser != null) {
+ try {
+ var next = parser.next()
+ while (next != XmlPullParser.END_DOCUMENT) {
+ when (next) {
+ XmlPullParser.START_TAG -> when (parser.name) {
+ "profile" -> {
+ return parser.getAttributeValue(null, "name")
+ }
+ }
}
+ next = parser.next()
}
+ } finally {
+ parser.close()
}
- next = it.next()
}
- null
+ return null
}
fun setProfile(context: Context, profile: String?) {
@@ -305,7 +342,7 @@ object ProfileManager {
val profileName = getProfileName { FileXmlResourceParser(file) } ?: return false
try {
Log.d(TAG, "Importing user profile '$profileName'")
- file.copyTo(getUserProfileFile(context))
+ file.copyTo(getUserProfileFile(context), overwrite = true)
if (activeProfile == PROFILE_USER) applyProfile(context, PROFILE_USER)
return true
} catch (e: Exception) {
diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/profile/ProfileProvider.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/profile/ProfileProvider.kt
new file mode 100644
index 00000000..53e4149f
--- /dev/null
+++ b/play-services-base-core/src/main/kotlin/org/microg/gms/profile/ProfileProvider.kt
@@ -0,0 +1,52 @@
+/*
+ * SPDX-FileCopyrightText: 2023 e Foundation
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.profile
+
+import android.content.ContentProvider
+import android.content.ContentValues
+import android.database.Cursor
+import android.database.MatrixCursor
+import android.net.Uri
+import org.microg.gms.settings.SettingsContract
+
+class ProfileProvider : ContentProvider() {
+
+ val COLUMN_ID = "profile_id"
+ val COLUMN_VALUE = "profile_value"
+
+ override fun onCreate(): Boolean {
+ ProfileManager.ensureInitialized(context!!)
+ return true
+ }
+
+ override fun query(
+ uri: Uri,
+ projection: Array?,
+ selection: String?,
+ selectionArgs: Array?,
+ sortOrder: String?
+ ): Cursor =
+ MatrixCursor(arrayOf(COLUMN_ID, COLUMN_VALUE)).apply {
+ ProfileManager.getActiveProfileData(context!!).entries
+ .forEach {
+ addRow(arrayOf(it.key, it.value))
+ }
+ }
+
+ override fun getType(uri: Uri): String {
+ return "vnd.android.cursor.item/vnd.${SettingsContract.getAuthority(context!!)}.${uri.path}"
+ }
+
+ override fun insert(uri: Uri, values: ContentValues?): Nothing = throw UnsupportedOperationException()
+
+ override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Nothing =
+ throw UnsupportedOperationException()
+
+ override fun update(
+ uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?
+ ): Nothing = throw UnsupportedOperationException()
+
+}
diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/MetaDataPreferences.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/MetaDataPreferences.kt
new file mode 100644
index 00000000..1e21f6d9
--- /dev/null
+++ b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/MetaDataPreferences.kt
@@ -0,0 +1,45 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.settings
+
+import android.content.Context
+import android.content.SharedPreferences
+import android.content.pm.PackageManager.GET_META_DATA
+import android.os.Bundle
+
+class MetaDataPreferences(private val context: Context, private val prefix: String = "") : SharedPreferences {
+ private val metaData by lazy {
+ runCatching { context.packageManager.getApplicationInfo(context.packageName, GET_META_DATA) }.getOrNull()?.metaData ?: Bundle.EMPTY
+ }
+
+ override fun getAll(): Map = metaData.keySet().filter { it.startsWith(prefix) }.associate { it.substring(prefix.length) to metaData.get(it) }
+
+ override fun getString(key: String, defValue: String?): String? = metaData.getString(prefix + key, defValue)
+
+ override fun getStringSet(key: String, defValues: Set?): Set? = metaData.getStringArray(prefix + key)?.toSet() ?: defValues
+
+ override fun getInt(key: String?, defValue: Int): Int = metaData.getInt(prefix + key, defValue)
+
+ override fun getLong(key: String?, defValue: Long): Long = metaData.getLong(prefix + key, defValue)
+
+ override fun getFloat(key: String?, defValue: Float): Float = metaData.getFloat(prefix + key, defValue)
+
+ override fun getBoolean(key: String?, defValue: Boolean): Boolean = metaData.getBoolean(prefix + key, defValue)
+
+ override fun contains(key: String?): Boolean = metaData.containsKey(prefix + key)
+
+ override fun edit(): SharedPreferences.Editor {
+ throw UnsupportedOperationException()
+ }
+
+ override fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) {
+ throw UnsupportedOperationException()
+ }
+
+ override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) {
+ throw UnsupportedOperationException()
+ }
+}
\ No newline at end of file
diff --git a/play-services-base-core/src/main/kotlin/org/microg/mgms/settings/SettingsContract.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt
similarity index 97%
rename from play-services-base-core/src/main/kotlin/org/microg/mgms/settings/SettingsContract.kt
rename to play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt
index 841b47a0..8851d1a1 100644
--- a/play-services-base-core/src/main/kotlin/org/microg/mgms/settings/SettingsContract.kt
+++ b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt
@@ -1,4 +1,4 @@
-package org.microg.mgms.settings
+package org.microg.gms.settings
import android.content.ContentValues
import android.content.Context
@@ -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"
@@ -81,10 +80,12 @@ object SettingsContract {
const val TRUST_GOOGLE = "auth_manager_trust_google"
const val VISIBLE = "auth_manager_visible"
+ const val INCLUDE_ANDROID_ID = "auth_include_android_id"
val PROJECTION = arrayOf(
TRUST_GOOGLE,
VISIBLE,
+ INCLUDE_ANDROID_ID,
)
}
diff --git a/play-services-base-core/src/main/kotlin/org/microg/mgms/settings/SettingsProvider.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt
similarity index 90%
rename from play-services-base-core/src/main/kotlin/org/microg/mgms/settings/SettingsProvider.kt
rename to play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt
index f1829b2c..39dc00e1 100644
--- a/play-services-base-core/src/main/kotlin/org/microg/mgms/settings/SettingsProvider.kt
+++ b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt
@@ -4,7 +4,7 @@
*/
@file:Suppress("DEPRECATION")
-package org.microg.mgms.settings
+package org.microg.gms.settings
import android.content.ContentProvider
import android.content.ContentValues
@@ -16,21 +16,20 @@ import android.database.MatrixCursor
import android.net.Uri
import android.preference.PreferenceManager
import org.microg.gms.common.PackageUtils.warnIfNotMainProcess
-import org.microg.mgms.settings.SettingsContract.Auth
-import org.microg.mgms.settings.SettingsContract.CheckIn
-import org.microg.mgms.settings.SettingsContract.Gcm
-import org.microg.mgms.settings.SettingsContract.Profile
-import org.microg.mgms.settings.SettingsContract.getAuthority
+import org.microg.gms.settings.SettingsContract.Auth
+import org.microg.gms.settings.SettingsContract.CheckIn
+import org.microg.gms.settings.SettingsContract.Gcm
+import org.microg.gms.settings.SettingsContract.Profile
+import org.microg.gms.settings.SettingsContract.getAuthority
import java.io.File
+private const val SETTINGS_PREFIX = "org.microg.gms.settings."
+
/**
* All settings access should go through this [ContentProvider],
* because it provides safe access from different processes which normal [SharedPreferences] don't.
*/
class SettingsProvider : ContentProvider() {
- companion object {
- const val INTERVAL = 1 * 60 * 1000 // 1 minute
- }
private val preferences: SharedPreferences by lazy {
PreferenceManager.getDefaultSharedPreferences(context)
@@ -50,6 +49,10 @@ class SettingsProvider : ContentProvider() {
}
}
+ private val metaDataPreferences: SharedPreferences by lazy {
+ MetaDataPreferences(context!!, SETTINGS_PREFIX)
+ }
+
override fun onCreate(): Boolean {
return true
}
@@ -97,7 +100,7 @@ class SettingsProvider : ContentProvider() {
CheckIn.VERSION_INFO -> checkInPrefs.getString(key, "") ?: ""
CheckIn.DEVICE_DATA_VERSION_INFO -> checkInPrefs.getString(key, "") ?: ""
CheckIn.BRAND_SPOOF -> getSettingsBoolean(key, false)
- CheckIn.HIDE_LAUNCHER_ICON -> getSettingsBoolean(key, false)
+ CheckIn.HIDE_LAUNCHER_ICON -> getSettingsBoolean(key, true)
else -> throw IllegalArgumentException()
}
}
@@ -165,9 +168,9 @@ class SettingsProvider : ContentProvider() {
Gcm.NETWORK_ROAMING -> Integer.parseInt(preferences.getString(key, "0") ?: "0")
Gcm.NETWORK_OTHER -> Integer.parseInt(preferences.getString(key, "0") ?: "0")
- Gcm.LEARNT_MOBILE -> preferences.getInt(key, Companion.INTERVAL)
- Gcm.LEARNT_WIFI -> preferences.getInt(key, Companion.INTERVAL)
- Gcm.LEARNT_OTHER -> preferences.getInt(key, Companion.INTERVAL)
+ Gcm.LEARNT_MOBILE -> preferences.getInt(key, 300000)
+ Gcm.LEARNT_WIFI -> preferences.getInt(key, 300000)
+ Gcm.LEARNT_OTHER -> preferences.getInt(key, 300000)
else -> throw IllegalArgumentException("Unknown key: $key")
}
@@ -202,6 +205,7 @@ class SettingsProvider : ContentProvider() {
when (key) {
Auth.TRUST_GOOGLE -> getSettingsBoolean(key, true)
Auth.VISIBLE -> getSettingsBoolean(key, false)
+ Auth.INCLUDE_ANDROID_ID -> getSettingsBoolean(key, true)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
@@ -213,6 +217,7 @@ class SettingsProvider : ContentProvider() {
when (key) {
Auth.TRUST_GOOGLE -> editor.putBoolean(key, value as Boolean)
Auth.VISIBLE -> editor.putBoolean(key, value as Boolean)
+ Auth.INCLUDE_ANDROID_ID -> editor.putBoolean(key, value as Boolean)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
@@ -267,12 +272,12 @@ class SettingsProvider : ContentProvider() {
* @return the current setting as [Int], because [ContentProvider] does not support [Boolean].
*/
private fun getSettingsBoolean(key: String, def: Boolean): Int {
- return listOf(preferences, systemDefaultPreferences).getBooleanAsInt(key, def)
+ return listOf(preferences, systemDefaultPreferences, metaDataPreferences).getBooleanAsInt(key, def)
}
- private fun getSettingsString(key: String, def: String? = null): String? = listOf(preferences, systemDefaultPreferences).getString(key, def)
- private fun getSettingsInt(key: String, def: Int): Int = listOf(preferences, systemDefaultPreferences).getInt(key, def)
- private fun getSettingsLong(key: String, def: Long): Long = listOf(preferences, systemDefaultPreferences).getLong(key, def)
+ private fun getSettingsString(key: String, def: String? = null): String? = listOf(preferences, systemDefaultPreferences, metaDataPreferences).getString(key, def)
+ private fun getSettingsInt(key: String, def: Int): Int = listOf(preferences, systemDefaultPreferences, metaDataPreferences).getInt(key, def)
+ private fun getSettingsLong(key: String, def: Long): Long = listOf(preferences, systemDefaultPreferences, metaDataPreferences).getLong(key, def)
private fun List.getString(key: String, def: String?): String? = foldRight(def) { preferences, defValue -> preferences?.getString(key, defValue) ?: defValue }
private fun List.getInt(key: String, def: Int): Int = foldRight(def) { preferences, defValue -> preferences?.getInt(key, defValue) ?: defValue }
diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/utils/BinderUtils.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/utils/BinderUtils.kt
index 79e8ff8f..226bb431 100644
--- a/play-services-base-core/src/main/kotlin/org/microg/gms/utils/BinderUtils.kt
+++ b/play-services-base-core/src/main/kotlin/org/microg/gms/utils/BinderUtils.kt
@@ -12,13 +12,13 @@ import android.util.Log
private const val TAG = "BinderUtils"
-fun IBinder.warnOnTransactionIssues(code: Int, reply: Parcel?, flags: Int, base: () -> Boolean): Boolean {
+fun IBinder.warnOnTransactionIssues(code: Int, reply: Parcel?, flags: Int, tag: String = TAG, base: () -> Boolean): Boolean {
if (base.invoke()) {
if ((flags and Binder.FLAG_ONEWAY) > 0 && (reply?.dataSize() ?: 0) > 0) {
- Log.w(TAG, "Method $code in $interfaceDescriptor is oneway, but returned data")
+ Log.w(tag, "Method $code in $interfaceDescriptor is oneway, but returned data")
}
return true
}
- Log.w(TAG, "Unknown method $code in $interfaceDescriptor, skipping")
+ Log.w(tag, "Unknown method $code in $interfaceDescriptor, skipping")
return (flags and Binder.FLAG_ONEWAY) > 0 // Don't return false on oneway transaction to suppress warning
}
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-base/build.gradle b/play-services-base/build.gradle
index 8857d222..e1cff12a 100644
--- a/play-services-base/build.gradle
+++ b/play-services-base/build.gradle
@@ -26,9 +26,10 @@ android {
}
compileOptions {
- sourceCompatibility = 1.8
- targetCompatibility = 1.8
+ sourceCompatibility = 17
+ targetCompatibility = 17
}
+ namespace 'org.microg.gms.base'
}
dependencies {
diff --git a/play-services-base/src/main/AndroidManifest.xml b/play-services-base/src/main/AndroidManifest.xml
index 3ab02d97..c31f1c05 100644
--- a/play-services-base/src/main/AndroidManifest.xml
+++ b/play-services-base/src/main/AndroidManifest.xml
@@ -15,8 +15,7 @@
~ limitations under the License.
-->
-
+
CREATOR = new AutoCreator<>(AccountInfo.class);
+ public static final Creator CREATOR = new AutoCreator(AccountInfo.class);
}
diff --git a/play-services-base/src/main/java/com/google/android/gms/common/api/Api.java b/play-services-base/src/main/java/com/google/android/gms/common/api/Api.java
index 065fff8a..fd91a375 100644
--- a/play-services-base/src/main/java/com/google/android/gms/common/api/Api.java
+++ b/play-services-base/src/main/java/com/google/android/gms/common/api/Api.java
@@ -20,6 +20,7 @@ import android.accounts.Account;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
+import org.microg.gms.common.Hide;
import org.microg.gms.common.PublicApi;
import org.microg.gms.common.api.ApiClientBuilder;
@@ -100,4 +101,14 @@ public final class Api {
}
}
+ @Hide
+ public interface Client {
+ void connect();
+
+ void disconnect();
+
+ boolean isConnected();
+
+ boolean isConnecting();
+ }
}
diff --git a/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApi.java b/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApi.java
index 54e2c63a..4a33737c 100644
--- a/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApi.java
+++ b/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApi.java
@@ -11,16 +11,18 @@ import com.google.android.gms.common.api.internal.ApiKey;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.TaskCompletionSource;
+import org.microg.gms.common.Hide;
import org.microg.gms.common.PublicApi;
-import org.microg.gms.common.api.ApiClient;
import org.microg.gms.common.api.GoogleApiManager;
import org.microg.gms.common.api.PendingGoogleApiCall;
@PublicApi
public abstract class GoogleApi implements HasApiKey {
- private final GoogleApiManager manager;
- @PublicApi(exclude = true)
+ private GoogleApiManager manager;
+ @Hide
public Api api;
+ @Hide
+ public O options;
@PublicApi(exclude = true)
protected GoogleApi(Context context, Api api) {
@@ -29,7 +31,14 @@ public abstract class GoogleApi implements HasApiKey Task scheduleTask(PendingGoogleApiCall apiCall) {
+ protected GoogleApi(Context context, Api api, O options) {
+ this.api = api;
+ this.manager = GoogleApiManager.getInstance(context);
+ this.options = options;
+ }
+
+ @PublicApi(exclude = true)
+ protected Task scheduleTask(PendingGoogleApiCall apiCall) {
TaskCompletionSource completionSource = new TaskCompletionSource<>();
manager.scheduleTask(this, apiCall, completionSource);
return completionSource.getTask();
@@ -43,6 +52,6 @@ public abstract class GoogleApi implements HasApiKey apis = new HashMap<>();
- private final Set connectionCallbacks = new HashSet<>();
- private final Set connectionFailedListeners = new HashSet<>();
- private final Set scopes = new HashSet<>();
+ private final Map apis = new HashMap();
+ private final Set connectionCallbacks = new HashSet();
+ private final Set connectionFailedListeners = new HashSet();
+ private final Set scopes = new HashSet();
private String accountName;
private int clientId = -1;
private FragmentActivity fragmentActivity;
@@ -364,7 +364,12 @@ public interface GoogleApiClient {
}
private ApiClientSettings getClientSettings() {
- return null;
+ ApiClientSettings clientSettings = new ApiClientSettings();
+ clientSettings.accountName = accountName;
+ clientSettings.scopes = new HashSet<>(scopes);
+ clientSettings.gravityForPopups = gravityForPopups;
+ clientSettings.viewForPopups = viewForPopups;
+ return clientSettings;
}
public Builder enableAutoManage(FragmentActivity fragmentActivity, int cliendId,
@@ -444,6 +449,8 @@ public interface GoogleApiClient {
* A suspension cause informing you that a peer device connection was lost.
*/
int CAUSE_NETWORK_LOST = 2;
+
+ void onConnected(Bundle connectionHint);
}
/**
diff --git a/play-services-base/src/main/java/com/google/android/gms/common/api/PendingResult.java b/play-services-base/src/main/java/com/google/android/gms/common/api/PendingResult.java
index e3881366..ec162920 100644
--- a/play-services-base/src/main/java/com/google/android/gms/common/api/PendingResult.java
+++ b/play-services-base/src/main/java/com/google/android/gms/common/api/PendingResult.java
@@ -40,20 +40,20 @@ public interface PendingResult {
* Blocks until the task is completed. This is not allowed on the UI thread. The returned
* result object can have an additional failure mode of INTERRUPTED.
*/
- R await();
+ public R await();
/**
* Blocks until the task is completed or has timed out waiting for the result. This is not
* allowed on the UI thread. The returned result object can have an additional failure mode
* of either INTERRUPTED or TIMEOUT.
*/
- R await(long time, TimeUnit unit);
+ public R await(long time, TimeUnit unit);
- void cancel();
+ public void cancel();
- boolean isCanceled();
+ public boolean isCanceled();
- void setResultCallback(ResultCallback callback, long time, TimeUnit unit);
+ public void setResultCallback(ResultCallback callback, long time, TimeUnit unit);
- void setResultCallback(ResultCallback callback);
+ public void setResultCallback(ResultCallback callback);
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/DummyApiClient.java b/play-services-base/src/main/java/org/microg/gms/common/DummyApiClient.java
index 132a6148..c527866f 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/DummyApiClient.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/DummyApiClient.java
@@ -16,9 +16,9 @@
package org.microg.gms.common;
-import org.microg.gms.common.api.ApiClient;
+import com.google.android.gms.common.api.Api;
-public class DummyApiClient implements ApiClient {
+public class DummyApiClient implements Api.Client {
private boolean connected = false;
@Override
diff --git a/play-services-base/src/main/java/org/microg/gms/common/GmsClient.java b/play-services-base/src/main/java/org/microg/gms/common/GmsClient.java
index 8b816fd8..e5b71717 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/GmsClient.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/GmsClient.java
@@ -27,16 +27,17 @@ import android.os.RemoteException;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.CommonStatusCodes;
+import com.google.android.gms.common.internal.ConnectionInfo;
import com.google.android.gms.common.internal.GetServiceRequest;
import com.google.android.gms.common.internal.IGmsCallbacks;
import com.google.android.gms.common.internal.IGmsServiceBroker;
-import org.microg.gms.common.api.ApiClient;
import org.microg.gms.common.api.ConnectionCallbacks;
import org.microg.gms.common.api.OnConnectionFailedListener;
-public abstract class GmsClient implements ApiClient {
+public abstract class GmsClient implements Api.Client {
private static final String TAG = "GmsClient";
private final Context context;
@@ -47,6 +48,9 @@ public abstract class GmsClient implements ApiClient {
private I serviceInterface;
private final String actionString;
+ protected boolean requireMicrog;
+ protected String packageName;
+
protected int serviceId = -1;
protected Account account = null;
protected Bundle extras = new Bundle();
@@ -56,6 +60,8 @@ public abstract class GmsClient implements ApiClient {
this.callbacks = callbacks;
this.connectionFailedListener = connectionFailedListener;
this.actionString = actionString;
+ this.requireMicrog = false;
+ this.packageName = context.getPackageName();
}
protected void onConnectedToBroker(IGmsServiceBroker broker, GmsCallbacks callbacks) throws RemoteException {
@@ -63,8 +69,7 @@ public abstract class GmsClient implements ApiClient {
throw new IllegalStateException("Service ID not set in constructor and onConnectedToBroker not implemented");
}
GetServiceRequest request = new GetServiceRequest(serviceId);
- request.extras = new Bundle();
- request.packageName = context.getPackageName();
+ request.packageName = packageName;
request.account = account;
request.extras = extras;
broker.getService(callbacks, request);
@@ -83,7 +88,7 @@ public abstract class GmsClient implements ApiClient {
MultiConnectionKeeper.getInstance(context).unbind(actionString, serviceConnection);
}
serviceConnection = new GmsServiceConnection();
- if (!MultiConnectionKeeper.getInstance(context).bind(actionString, serviceConnection)) {
+ if (!MultiConnectionKeeper.getInstance(context).bind(actionString, serviceConnection, requireMicrog)) {
state = ConnectionState.ERROR;
handleConnectionFailed();
}
@@ -184,5 +189,16 @@ public abstract class GmsClient implements ApiClient {
callbacks.onConnected(params);
}
}
+
+ @Override
+ public void onAccountValidationComplete(int statusCode, Bundle params) throws RemoteException {
+ Log.d(TAG, "GmsCallbacks : onAccountValidationComplete");
+ }
+
+ @Override
+ public void onPostInitCompleteWithConnectionInfo(int statusCode, IBinder binder, ConnectionInfo info) throws RemoteException {
+ onPostInitComplete(statusCode, binder, info == null ? null : info.params);
+ }
}
+
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/GmsConnector.java b/play-services-base/src/main/java/org/microg/gms/common/GmsConnector.java
index 9a56566c..b77c6d2c 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/GmsConnector.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/GmsConnector.java
@@ -27,10 +27,9 @@ import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Result;
import org.microg.gms.common.api.AbstractPendingResult;
-import org.microg.gms.common.api.ApiClient;
import org.microg.gms.common.api.GoogleApiClientImpl;
-public class GmsConnector {
+public class GmsConnector {
private static final String TAG = "GmsConnector";
private final GoogleApiClientImpl apiClient;
@@ -43,8 +42,8 @@ public class GmsConnector {
this.callback = callback;
}
- public static PendingResult call(GoogleApiClient client, Api api, GmsConnector.Callback callback) {
- return new GmsConnector<>(client, api, callback).connect();
+ public static PendingResult call(GoogleApiClient client, Api api, GmsConnector.Callback callback) {
+ return new GmsConnector(client, api, callback).connect();
}
public AbstractPendingResult connect() {
@@ -52,7 +51,7 @@ public class GmsConnector {
apiClient.incrementUsageCounter();
apiClient.getApiConnection(api);
Looper looper = apiClient.getLooper();
- final AbstractPendingResult result = new AbstractPendingResult<>(looper);
+ final AbstractPendingResult result = new AbstractPendingResult(looper);
Message msg = new Message();
msg.obj = result;
new Handler(looper).sendMessage(msg);
@@ -78,9 +77,12 @@ public class GmsConnector {
final AbstractPendingResult result = (AbstractPendingResult) msg.obj;
try {
C connection = (C) apiClient.getApiConnection(api);
- callback.onClientAvailable(connection, realResult -> {
- result.deliverResult(realResult);
- apiClient.decrementUsageCounter();
+ callback.onClientAvailable(connection, new GmsConnector.Callback.ResultProvider() {
+ @Override
+ public void onResultAvailable(R realResult) {
+ result.deliverResult(realResult);
+ apiClient.decrementUsageCounter();
+ }
});
} catch (RemoteException ignored) {
diff --git a/play-services-base/src/main/java/org/microg/gms/common/MultiConnectionKeeper.java b/play-services-base/src/main/java/org/microg/gms/common/MultiConnectionKeeper.java
index 913291f4..616224bf 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/MultiConnectionKeeper.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/MultiConnectionKeeper.java
@@ -16,13 +16,15 @@
package org.microg.gms.common;
-import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
-
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ResolveInfo;
import android.os.IBinder;
import android.util.Log;
@@ -31,14 +33,15 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
+
public class MultiConnectionKeeper {
private static final String TAG = "GmsMultiConKeeper";
- @SuppressLint("StaticFieldLeak")
private static MultiConnectionKeeper INSTANCE;
private final Context context;
- private final Map connections = new HashMap<>();
+ private final Map connections = new HashMap();
public MultiConnectionKeeper(Context context) {
this.context = context;
@@ -46,13 +49,17 @@ public class MultiConnectionKeeper {
public synchronized static MultiConnectionKeeper getInstance(Context context) {
if (INSTANCE == null)
- INSTANCE = new MultiConnectionKeeper(context);
+ INSTANCE = new MultiConnectionKeeper(context.getApplicationContext());
return INSTANCE;
}
public synchronized boolean bind(String action, ServiceConnection connection) {
- Log.d(TAG, "bind(" + action + ", " + connection + ")");
+ return bind(action, connection, false);
+ }
+
+ public synchronized boolean bind(String action, ServiceConnection connection, boolean requireMicrog) {
Connection con = connections.get(action);
+ Log.d(TAG, "bind(" + action + ", " + connection + ", " + requireMicrog + ") has=" + (con != null));
if (con != null) {
if (!con.forwardsConnection(connection)) {
con.addConnectionForward(connection);
@@ -60,11 +67,12 @@ public class MultiConnectionKeeper {
con.bind();
}
} else {
- con = new Connection(action);
+ con = new Connection(action, requireMicrog);
con.addConnectionForward(connection);
con.bind();
connections.put(action, con);
}
+ Log.d(TAG, "bind() : bound=" + con.isBound());
return con.isBound();
}
@@ -73,21 +81,26 @@ public class MultiConnectionKeeper {
Connection con = connections.get(action);
if (con != null) {
con.removeConnectionForward(connection);
- if (!con.hasForwards() && con.isBound()) {
- con.unbind();
- connections.remove(action);
+ if (con.isBound()) {
+ if (!con.hasForwards()) {
+ con.unbind();
+ connections.remove(action);
+ } else {
+ Log.d(TAG, "Not unbinding for " + connection + ": has pending other bindings on action " + action);
+ }
}
}
}
public class Connection {
private final String actionString;
- private final Set connectionForwards = new HashSet<>();
+ private final boolean requireMicrog;
+ private final Set connectionForwards = new HashSet();
private boolean bound = false;
private boolean connected = false;
private IBinder binder;
private ComponentName component;
- private final ServiceConnection serviceConnection = new ServiceConnection() {
+ private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.d(TAG, "Connection(" + actionString + ") : ServiceConnection : " +
@@ -115,7 +128,12 @@ public class MultiConnectionKeeper {
};
public Connection(String actionString) {
+ this(actionString, false);
+ }
+
+ public Connection(String actionString, boolean requireMicrog) {
this.actionString = actionString;
+ this.requireMicrog = requireMicrog;
}
@SuppressLint("InlinedApi")
@@ -124,29 +142,53 @@ public class MultiConnectionKeeper {
Intent gmsIntent = new Intent(actionString).setPackage(GMS_PACKAGE_NAME);
Intent selfIntent = new Intent(actionString).setPackage(context.getPackageName());
Intent intent;
- if (context.getPackageManager().resolveService(gmsIntent, 0) == null) {
+ ResolveInfo resolveInfo;
+ if ((resolveInfo = context.getPackageManager().resolveService(gmsIntent, 0)) == null) {
Log.w(TAG, "No GMS service found for " + actionString);
if (context.getPackageManager().resolveService(selfIntent, 0) != null) {
- Log.d(TAG, "Found service for "+actionString+" in self package, using it instead");
+ Log.d(TAG, "Found service for " + actionString + " in self package, using it instead");
intent = selfIntent;
} else {
return;
}
+ } else if (requireMicrog && !isMicrog(resolveInfo)) {
+ Log.w(TAG, "GMS service found for " + actionString + " but looks not like microG");
+ if (context.getPackageManager().resolveService(selfIntent, 0) != null) {
+ Log.d(TAG, "Found service for " + actionString + " in self package, using it instead");
+ intent = selfIntent;
+ } else {
+ intent = gmsIntent;
+ }
} else {
intent = gmsIntent;
}
- int flags = Context.BIND_AUTO_CREATE;
- flags |= Context.BIND_ADJUST_WITH_ACTIVITY;
+ int flags = Context.BIND_AUTO_CREATE | Context.BIND_DEBUG_UNBIND | Context.BIND_ADJUST_WITH_ACTIVITY;
bound = context.bindService(intent, serviceConnection, flags);
+ Log.d(TAG, "Connection(" + actionString + ") : bind() : bindService=" + bound);
if (!bound) {
context.unbindService(serviceConnection);
}
}
+ public boolean isMicrog(ResolveInfo resolveInfo) {
+ if (resolveInfo == null || resolveInfo.serviceInfo == null) return false;
+ if (resolveInfo.serviceInfo.name.startsWith("org.microg.")) return true;
+ try {
+ PermissionInfo info = context.getPackageManager().getPermissionInfo("org.microg.gms.EXTENDED_ACCESS", 0);
+ return info.packageName.equals(resolveInfo.serviceInfo.packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
public boolean isBound() {
return bound;
}
+ public IBinder getBinder() {
+ return binder;
+ }
+
public void unbind() {
Log.d(TAG, "Connection(" + actionString + ") : unbind()");
try {
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/AbstractPendingResult.java b/play-services-base/src/main/java/org/microg/gms/common/api/AbstractPendingResult.java
index 560f3681..15aac9e3 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/AbstractPendingResult.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/AbstractPendingResult.java
@@ -34,7 +34,7 @@ public class AbstractPendingResult implements PendingResult
private ResultCallback resultCallback;
public AbstractPendingResult(Looper looper) {
- handler = new ResultCallbackHandler<>(looper);
+ handler = new ResultCallbackHandler(looper);
}
private R getResult() {
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClient.java b/play-services-base/src/main/java/org/microg/gms/common/api/ApiClient.java
deleted file mode 100644
index 602e150e..00000000
--- a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClient.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2013-2017 microG Project Team
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.microg.gms.common.api;
-
-public interface ApiClient {
- void connect();
-
- void disconnect();
-
- boolean isConnected();
-
- boolean isConnecting();
-}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientBuilder.java b/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientBuilder.java
index b5aa386f..18336fa5 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientBuilder.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientBuilder.java
@@ -22,5 +22,5 @@ import android.os.Looper;
import com.google.android.gms.common.api.Api;
public interface ApiClientBuilder {
- ApiClient build(O options, Context context, Looper looper, ApiClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener);
+ Api.Client build(O options, Context context, Looper looper, ApiClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener);
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientSettings.java b/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientSettings.java
index d1e314a7..af67e799 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientSettings.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientSettings.java
@@ -5,5 +5,15 @@
package org.microg.gms.common.api;
+import android.view.View;
+
+import java.util.Set;
+
public class ApiClientSettings {
+ public String accountName;
+ public String packageName;
+ public Integer sessionId;
+ public Set scopes;
+ public int gravityForPopups;
+ public View viewForPopups;
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiClientImpl.java b/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiClientImpl.java
index e59f68f6..2dffa374 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiClientImpl.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiClientImpl.java
@@ -19,10 +19,11 @@ package org.microg.gms.common.api;
import android.content.Context;
import android.os.Bundle;
import android.os.Looper;
-import android.util.Log;
import androidx.fragment.app.FragmentActivity;
+import android.util.Log;
+
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.GoogleApiClient;
@@ -41,10 +42,10 @@ public class GoogleApiClientImpl implements GoogleApiClient {
private final Context context;
private final Looper looper;
private final ApiClientSettings clientSettings;
- private final Map apis = new HashMap<>();
- private final Map apiConnections = new HashMap<>();
- private final Set connectionCallbacks = new HashSet<>();
- private final Set connectionFailedListeners = new HashSet<>();
+ private final Map apis = new HashMap();
+ private final Map apiConnections = new HashMap();
+ private final Set connectionCallbacks = new HashSet();
+ private final Set connectionFailedListeners = new HashSet();
private final int clientId;
private final ConnectionCallbacks baseConnectionCallbacks = new ConnectionCallbacks() {
@Override
@@ -63,12 +64,16 @@ public class GoogleApiClientImpl implements GoogleApiClient {
}
}
};
- private final OnConnectionFailedListener baseConnectionFailedListener = result -> {
- Log.d(TAG, "OnConnectionFailedListener : onConnectionFailed()");
- for (OnConnectionFailedListener listener : connectionFailedListeners) {
- listener.onConnectionFailed(result);
- }
- };
+ private final OnConnectionFailedListener baseConnectionFailedListener = new
+ OnConnectionFailedListener() {
+ @Override
+ public void onConnectionFailed(ConnectionResult result) {
+ Log.d(TAG, "OnConnectionFailedListener : onConnectionFailed()");
+ for (OnConnectionFailedListener listener : connectionFailedListeners) {
+ listener.onConnectionFailed(result);
+ }
+ }
+ };
private int usageCounter = 0;
private boolean shouldDisconnect = false;
@@ -84,6 +89,10 @@ public class GoogleApiClientImpl implements GoogleApiClient {
this.connectionFailedListeners.addAll(connectionFailedListeners);
this.clientId = clientId;
+ if (this.clientSettings.sessionId == null) {
+ this.clientSettings.sessionId = hashCode();
+ }
+
for (Api api : apis.keySet()) {
apiConnections.put(api, api.getBuilder().build(apis.get(api), context, looper, clientSettings, baseConnectionCallbacks, baseConnectionFailedListener));
}
@@ -102,7 +111,7 @@ public class GoogleApiClientImpl implements GoogleApiClient {
return looper;
}
- public ApiClient getApiConnection(Api api) {
+ public Api.Client getApiConnection(Api api) {
return apiConnections.get(api);
}
@@ -132,7 +141,7 @@ public class GoogleApiClientImpl implements GoogleApiClient {
Log.d(TAG, "Already connected/connecting, nothing to do");
return;
}
- for (ApiClient connection : apiConnections.values()) {
+ for (Api.Client connection : apiConnections.values()) {
if (!connection.isConnected()) {
connection.connect();
}
@@ -145,7 +154,7 @@ public class GoogleApiClientImpl implements GoogleApiClient {
shouldDisconnect = true;
} else {
Log.d(TAG, "disconnect()");
- for (ApiClient connection : apiConnections.values()) {
+ for (Api.Client connection : apiConnections.values()) {
if (connection.isConnected()) {
connection.disconnect();
}
@@ -155,7 +164,7 @@ public class GoogleApiClientImpl implements GoogleApiClient {
@Override
public synchronized boolean isConnected() {
- for (ApiClient connection : apiConnections.values()) {
+ for (Api.Client connection : apiConnections.values()) {
if (!connection.isConnected()) return false;
}
return true;
@@ -163,7 +172,7 @@ public class GoogleApiClientImpl implements GoogleApiClient {
@Override
public synchronized boolean isConnecting() {
- for (ApiClient connection : apiConnections.values()) {
+ for (Api.Client connection : apiConnections.values()) {
if (connection.isConnecting()) return true;
}
return false;
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiManager.java b/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiManager.java
index 4e05aa75..5cf7933e 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiManager.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiManager.java
@@ -11,19 +11,19 @@ import android.os.Bundle;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.GoogleApi;
+import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.TaskCompletionSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
public class GoogleApiManager {
private static GoogleApiManager instance;
- private final Context context;
- private final Map clientMap = new HashMap<>();
- private final Map>> waitingApiCallMap = new HashMap<>();
+ private Context context;
+ private Map clientMap = new HashMap<>();
+ private Map>> waitingApiCallMap = new HashMap<>();
private GoogleApiManager(Context context) {
this.context = context;
@@ -34,26 +34,30 @@ public class GoogleApiManager {
return instance;
}
- private synchronized A clientForApi(GoogleApi api) {
+ private synchronized A clientForApi(GoogleApi api) {
ApiInstance apiInstance = new ApiInstance(api);
if (clientMap.containsKey(apiInstance)) {
return (A) clientMap.get(apiInstance);
} else {
- ApiClient client = api.api.getBuilder().build(api.getOptions(), context, context.getMainLooper(), null, new ConnectionCallback(apiInstance), new ConnectionFailedListener(apiInstance));
+ Api.Client client = api.api.getBuilder().build(api.getOptions(), context, context.getMainLooper(), null, new ConnectionCallback(apiInstance), new ConnectionFailedListener(apiInstance));
clientMap.put(apiInstance, client);
waitingApiCallMap.put(apiInstance, new ArrayList<>());
return (A) client;
}
}
- public synchronized void scheduleTask(GoogleApi api, PendingGoogleApiCall apiCall, TaskCompletionSource completionSource) {
+ public synchronized void scheduleTask(GoogleApi api, PendingGoogleApiCall apiCall, TaskCompletionSource completionSource) {
A client = clientForApi(api);
boolean connecting = client.isConnecting();
boolean connected = client.isConnected();
if (connected) {
- apiCall.execute(client, completionSource);
+ try {
+ apiCall.execute(client, completionSource);
+ } catch (Exception e) {
+ completionSource.setException(e);
+ }
} else {
- waitingApiCallMap.get(new ApiInstance(api)).add(new WaitingApiCall<>((PendingGoogleApiCall) apiCall, completionSource));
+ waitingApiCallMap.get(new ApiInstance(api)).add(new WaitingApiCall((PendingGoogleApiCall) apiCall, completionSource));
if (!connecting) {
client.connect();
}
@@ -63,7 +67,11 @@ public class GoogleApiManager {
private synchronized void onInstanceConnected(ApiInstance apiInstance, Bundle connectionHint) {
List> waitingApiCalls = waitingApiCallMap.get(apiInstance);
for (WaitingApiCall> waitingApiCall : waitingApiCalls) {
- waitingApiCall.execute(clientMap.get(apiInstance));
+ try {
+ waitingApiCall.execute(clientMap.get(apiInstance));
+ } catch (Exception e) {
+ waitingApiCall.failed(e);
+ }
}
waitingApiCalls.clear();
}
@@ -81,7 +89,7 @@ public class GoogleApiManager {
}
private class ConnectionCallback implements ConnectionCallbacks {
- private final ApiInstance apiInstance;
+ private ApiInstance apiInstance;
public ConnectionCallback(ApiInstance apiInstance) {
this.apiInstance = apiInstance;
@@ -99,7 +107,7 @@ public class GoogleApiManager {
}
private class ConnectionFailedListener implements OnConnectionFailedListener {
- private final ApiInstance apiInstance;
+ private ApiInstance apiInstance;
public ConnectionFailedListener(ApiInstance apiInstance) {
this.apiInstance = apiInstance;
@@ -112,15 +120,15 @@ public class GoogleApiManager {
}
private static class WaitingApiCall {
- private final PendingGoogleApiCall apiCall;
- private final TaskCompletionSource completionSource;
+ private PendingGoogleApiCall apiCall;
+ private TaskCompletionSource completionSource;
- public WaitingApiCall(PendingGoogleApiCall apiCall, TaskCompletionSource completionSource) {
+ public WaitingApiCall(PendingGoogleApiCall apiCall, TaskCompletionSource completionSource) {
this.apiCall = apiCall;
this.completionSource = completionSource;
}
- public void execute(ApiClient client) {
+ public void execute(Api.Client client) throws Exception {
apiCall.execute(client, completionSource);
}
@@ -135,8 +143,8 @@ public class GoogleApiManager {
WaitingApiCall> that = (WaitingApiCall>) o;
- if (!Objects.equals(apiCall, that.apiCall)) return false;
- return Objects.equals(completionSource, that.completionSource);
+ if (apiCall != null ? !apiCall.equals(that.apiCall) : that.apiCall != null) return false;
+ return completionSource != null ? completionSource.equals(that.completionSource) : that.completionSource == null;
}
@Override
@@ -148,8 +156,8 @@ public class GoogleApiManager {
}
private static class ApiInstance {
- private final Class> apiClass;
- private final Api.ApiOptions apiOptions;
+ private Class> apiClass;
+ private Api.ApiOptions apiOptions;
public ApiInstance(Class> apiClass, Api.ApiOptions apiOptions) {
this.apiClass = apiClass;
@@ -167,8 +175,8 @@ public class GoogleApiManager {
ApiInstance that = (ApiInstance) o;
- if (!Objects.equals(apiClass, that.apiClass)) return false;
- return Objects.equals(apiOptions, that.apiOptions);
+ if (apiClass != null ? !apiClass.equals(that.apiClass) : that.apiClass != null) return false;
+ return apiOptions != null ? apiOptions.equals(that.apiOptions) : that.apiOptions == null;
}
@Override
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/PendingGoogleApiCall.java b/play-services-base/src/main/java/org/microg/gms/common/api/PendingGoogleApiCall.java
index 8c92abd7..578d02b9 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/PendingGoogleApiCall.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/PendingGoogleApiCall.java
@@ -5,8 +5,9 @@
package org.microg.gms.common.api;
+import com.google.android.gms.common.api.Api;
import com.google.android.gms.tasks.TaskCompletionSource;
-public interface PendingGoogleApiCall {
- void execute(A client, TaskCompletionSource completionSource);
+public interface PendingGoogleApiCall {
+ void execute(A client, TaskCompletionSource completionSource) throws Exception;
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/ResultCallbackHandler.java b/play-services-base/src/main/java/org/microg/gms/common/api/ResultCallbackHandler.java
index 1ddb4d47..c19c849c 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/ResultCallbackHandler.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/ResultCallbackHandler.java
@@ -50,7 +50,7 @@ class ResultCallbackHandler extends Handler {
public void sendResultCallback(ResultCallback callback, R result) {
Message message = new Message();
message.what = CALLBACK_ON_COMPLETE;
- message.obj = new OnCompleteObject<>(callback, result);
+ message.obj = new OnCompleteObject(callback, result);
sendMessage(message);
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/InstantGoogleApiCall.java b/play-services-base/src/main/java/org/microg/gms/common/api/ReturningGoogleApiCall.java
similarity index 77%
rename from play-services-base/src/main/java/org/microg/gms/common/api/InstantGoogleApiCall.java
rename to play-services-base/src/main/java/org/microg/gms/common/api/ReturningGoogleApiCall.java
index 5e813d8b..f836b9d4 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/InstantGoogleApiCall.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/ReturningGoogleApiCall.java
@@ -5,9 +5,10 @@
package org.microg.gms.common.api;
+import com.google.android.gms.common.api.Api;
import com.google.android.gms.tasks.TaskCompletionSource;
-public interface InstantGoogleApiCall extends PendingGoogleApiCall {
+public interface ReturningGoogleApiCall extends PendingGoogleApiCall {
R execute(A client) throws Exception;
@Override
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/VoidReturningGoogleApiCall.java b/play-services-base/src/main/java/org/microg/gms/common/api/VoidReturningGoogleApiCall.java
new file mode 100644
index 00000000..ee8cbf66
--- /dev/null
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/VoidReturningGoogleApiCall.java
@@ -0,0 +1,23 @@
+/*
+ * SPDX-FileCopyrightText: 2022 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.common.api;
+
+import com.google.android.gms.common.api.Api;
+import com.google.android.gms.tasks.TaskCompletionSource;
+
+public interface VoidReturningGoogleApiCall extends PendingGoogleApiCall{
+ void execute(A client) throws Exception;
+
+ @Override
+ default void execute(A client, TaskCompletionSource completionSource) {
+ try {
+ execute(client);
+ completionSource.setResult(null);
+ } catch (Exception e) {
+ completionSource.setException(e);
+ }
+ }
+}
diff --git a/play-services-basement/build.gradle b/play-services-basement/build.gradle
index 9499e1c3..9884e3c9 100644
--- a/play-services-basement/build.gradle
+++ b/play-services-basement/build.gradle
@@ -18,7 +18,7 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
dependencies {
- api "org.microg:safe-parcel:1.7.0"
+ api "org.microg:safe-parcel:$safeParcelVersion"
// Dependencies from play-services-basement:18.0.0
api "androidx.collection:collection:$collectionVersion"
@@ -39,10 +39,12 @@ android {
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
buildConfigField "int", "VERSION_CODE", "$appVersionCode"
+ buildConfigField "String", "BASE_PACKAGE_NAME", "\"$basePackageName\""
}
buildFeatures {
viewBinding = true
+ aidl true
}
sourceSets {
@@ -50,7 +52,8 @@ android {
}
compileOptions {
- sourceCompatibility = 1.8
- targetCompatibility = 1.8
+ sourceCompatibility = 17
+ targetCompatibility = 17
}
+ namespace 'org.microg.gms.basement'
}
\ No newline at end of file
diff --git a/play-services-basement/src/main/AndroidManifest.xml b/play-services-basement/src/main/AndroidManifest.xml
index bd436773..359a9b71 100644
--- a/play-services-basement/src/main/AndroidManifest.xml
+++ b/play-services-basement/src/main/AndroidManifest.xml
@@ -15,4 +15,4 @@
~ limitations under the License.
-->
-
+
diff --git a/play-services-basement/src/main/aidl/com/google/android/gms/common/ConnectionResult.aidl b/play-services-basement/src/main/aidl/com/google/android/gms/common/ConnectionResult.aidl
new file mode 100644
index 00000000..e46e6d5d
--- /dev/null
+++ b/play-services-basement/src/main/aidl/com/google/android/gms/common/ConnectionResult.aidl
@@ -0,0 +1,3 @@
+package com.google.android.gms.common;
+
+parcelable ConnectionResult;
\ No newline at end of file
diff --git a/play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesLookupQuery.aidl b/play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesLookupQuery.aidl
new file mode 100644
index 00000000..fab15aa1
--- /dev/null
+++ b/play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesLookupQuery.aidl
@@ -0,0 +1,3 @@
+package com.google.android.gms.common;
+
+parcelable GoogleCertificatesLookupQuery;
\ No newline at end of file
diff --git a/play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesLookupResponse.aidl b/play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesLookupResponse.aidl
new file mode 100644
index 00000000..e9b4bff3
--- /dev/null
+++ b/play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesLookupResponse.aidl
@@ -0,0 +1,3 @@
+package com.google.android.gms.common;
+
+parcelable GoogleCertificatesLookupResponse;
\ No newline at end of file
diff --git a/play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesQuery.aidl b/play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesQuery.aidl
new file mode 100644
index 00000000..e6aedfef
--- /dev/null
+++ b/play-services-basement/src/main/aidl/com/google/android/gms/common/GoogleCertificatesQuery.aidl
@@ -0,0 +1,3 @@
+package com.google.android.gms.common;
+
+parcelable GoogleCertificatesQuery;
\ No newline at end of file
diff --git a/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ConnectionInfo.aidl b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ConnectionInfo.aidl
new file mode 100644
index 00000000..b393f11d
--- /dev/null
+++ b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ConnectionInfo.aidl
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal;
+parcelable ConnectionInfo;
diff --git a/play-services-api/src/main/aidl/com/google/android/gms/common/internal/ICertData.aidl b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ICertData.aidl
similarity index 100%
rename from play-services-api/src/main/aidl/com/google/android/gms/common/internal/ICertData.aidl
rename to play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ICertData.aidl
diff --git a/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGmsCallbacks.aidl b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGmsCallbacks.aidl
index b0210281..8fe63347 100644
--- a/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGmsCallbacks.aidl
+++ b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGmsCallbacks.aidl
@@ -1,7 +1,15 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
package com.google.android.gms.common.internal;
import android.os.Bundle;
+import com.google.android.gms.common.internal.ConnectionInfo;
interface IGmsCallbacks {
void onPostInitComplete(int statusCode, IBinder binder, in Bundle params);
+ void onAccountValidationComplete(int statusCode, in Bundle params);
+ void onPostInitCompleteWithConnectionInfo(int statusCode, IBinder binder, in ConnectionInfo info);
}
diff --git a/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGoogleCertificatesApi.aidl b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGoogleCertificatesApi.aidl
new file mode 100644
index 00000000..6d54ad26
--- /dev/null
+++ b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGoogleCertificatesApi.aidl
@@ -0,0 +1,18 @@
+package com.google.android.gms.common.internal;
+
+import com.google.android.gms.common.GoogleCertificatesLookupQuery;
+import com.google.android.gms.common.GoogleCertificatesLookupResponse;
+import com.google.android.gms.common.GoogleCertificatesQuery;
+import com.google.android.gms.dynamic.IObjectWrapper;
+
+interface IGoogleCertificatesApi {
+ IObjectWrapper getGoogleCertificates() = 0;
+ IObjectWrapper getGoogleReleaseCertificates() = 1;
+ boolean isGoogleReleaseSigned(String packageName, IObjectWrapper certData) = 2;
+ boolean isGoogleSigned(String packageName, IObjectWrapper certData) = 3;
+ boolean isGoogleOrPlatformSigned(in GoogleCertificatesQuery query, IObjectWrapper packageManager) = 4;
+ GoogleCertificatesLookupResponse isPackageGoogleOrPlatformSigned(in GoogleCertificatesLookupQuery query) = 5;
+ boolean isPackageGoogleOrPlatformSignedAvailable() = 6;
+ GoogleCertificatesLookupResponse queryPackageSigned(in GoogleCertificatesLookupQuery query) = 7;
+ boolean isFineGrainedPackageVerificationAvailable() = 8;
+}
\ No newline at end of file
diff --git a/play-services-api/src/main/aidl/com/google/android/gms/common/internal/ISignInButtonCreator.aidl b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ISignInButtonCreator.aidl
similarity index 100%
rename from play-services-api/src/main/aidl/com/google/android/gms/common/internal/ISignInButtonCreator.aidl
rename to play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ISignInButtonCreator.aidl
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesLookupQuery.java b/play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesLookupQuery.java
new file mode 100644
index 00000000..ab8da97a
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesLookupQuery.java
@@ -0,0 +1,50 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common;
+
+import android.content.Context;
+import android.os.Parcel;
+import androidx.annotation.NonNull;
+import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
+import com.google.android.gms.dynamic.IObjectWrapper;
+import com.google.android.gms.dynamic.ObjectWrapper;
+
+@SafeParcelable.Class
+public class GoogleCertificatesLookupQuery extends AbstractSafeParcelable {
+ @Field(value = 1, getterName = "getCallingPackage")
+ String callingPackage;
+ @Field(2)
+ boolean allowTestKeys;
+ @Field(3)
+ boolean ignoreTestKeysOverride;
+ @Field(4)
+ IObjectWrapper contextWrapper;
+ private Context context;
+ @Field(5)
+ boolean isChimeraPackage;
+ @Field(6)
+ boolean includeHashesInErrorMessage;
+
+ public String getCallingPackage() {
+ return callingPackage;
+ }
+
+ public Context getContext() {
+ if (context == null && contextWrapper != null) {
+ context = ObjectWrapper.unwrapTyped(contextWrapper, Context.class);
+ }
+ return context;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ CREATOR.writeToParcel(this, dest, flags);
+ }
+
+ public static final SafeParcelableCreatorAndWriter CREATOR = findCreator(GoogleCertificatesLookupQuery.class);
+}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesLookupResponse.java b/play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesLookupResponse.java
new file mode 100644
index 00000000..90e0ee3a
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesLookupResponse.java
@@ -0,0 +1,38 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common;
+
+import android.os.Parcel;
+import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
+
+@SafeParcelable.Class
+public class GoogleCertificatesLookupResponse extends AbstractSafeParcelable {
+ @Field(1)
+ public final boolean result;
+ @Field(2)
+ public final String errorMessage;
+ @Field(3)
+ public final int statusValue;
+ @Field(4)
+ public final int firstPartyStatusValue;
+
+ @Constructor
+ public GoogleCertificatesLookupResponse(@Param(1) boolean result, @Param(2) String errorMessage, @Param(3) int statusValue, @Param(4) int firstPartyStatusValue) {
+ this.result = result;
+ this.errorMessage = errorMessage;
+ this.statusValue = statusValue;
+ this.firstPartyStatusValue = firstPartyStatusValue;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ CREATOR.writeToParcel(this, out, flags);
+ }
+
+ public static final SafeParcelableCreatorAndWriter CREATOR = findCreator(GoogleCertificatesLookupResponse.class);
+}
diff --git a/play-services-api/src/main/java/com/google/android/gms/common/internal/GoogleCertificatesQuery.java b/play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesQuery.java
similarity index 57%
rename from play-services-api/src/main/java/com/google/android/gms/common/internal/GoogleCertificatesQuery.java
rename to play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesQuery.java
index c8240279..dce40a90 100644
--- a/play-services-api/src/main/java/com/google/android/gms/common/internal/GoogleCertificatesQuery.java
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/GoogleCertificatesQuery.java
@@ -1,41 +1,38 @@
/*
- * Copyright (C) 2019 microG Project Team
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
*/
-package com.google.android.gms.common.internal;
+package com.google.android.gms.common;
import android.os.IBinder;
+import android.os.Parcel;
import android.os.RemoteException;
-
+import androidx.annotation.NonNull;
+import com.google.android.gms.common.internal.CertData;
+import com.google.android.gms.common.internal.ICertData;
+import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.dynamic.ObjectWrapper;
+import org.microg.gms.common.Hide;
-import org.microg.safeparcel.AutoSafeParcelable;
-import org.microg.safeparcel.SafeParceled;
-
-public class GoogleCertificatesQuery extends AutoSafeParcelable {
- @SafeParceled(1)
- private String packageName;
- @SafeParceled(2)
- private IBinder certDataBinder;
+@Hide
+@SafeParcelable.Class
+public class GoogleCertificatesQuery extends AbstractSafeParcelable {
+ @Field(value = 1, getterName = "getCallingPackage")
+ String callingPackage;
+ @Field(2)
+ IBinder certDataBinder;
private CertData certData;
- @SafeParceled(3)
- private boolean allowNonRelease;
+ @Field(3)
+ boolean allowTestKeys;
+ @Field(4)
+ boolean ignoreTestKeysOverride;
- public String getPackageName() {
- return packageName;
+ public String getCallingPackage() {
+ return callingPackage;
}
public CertData getCertData() {
@@ -71,5 +68,10 @@ public class GoogleCertificatesQuery extends AutoSafeParcelable {
return certData;
}
- public static final Creator CREATOR = new AutoCreator(GoogleCertificatesQuery.class);
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ CREATOR.writeToParcel(this, dest, flags);
+ }
+
+ public static final SafeParcelableCreatorAndWriter CREATOR = findCreator(GoogleCertificatesQuery.class);
}
diff --git a/play-services-api/src/main/java/com/google/android/gms/common/internal/CertData.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/CertData.java
similarity index 100%
rename from play-services-api/src/main/java/com/google/android/gms/common/internal/CertData.java
rename to play-services-basement/src/main/java/com/google/android/gms/common/internal/CertData.java
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/ConnectionInfo.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/ConnectionInfo.java
new file mode 100644
index 00000000..19326d08
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/ConnectionInfo.java
@@ -0,0 +1,31 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import androidx.annotation.NonNull;
+import com.google.android.gms.common.Feature;
+import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
+
+@SafeParcelable.Class
+public class ConnectionInfo extends AbstractSafeParcelable {
+ @Field(1)
+ public Bundle params;
+ @Field(2)
+ public Feature[] features;
+ @Field(3)
+ public int unknown3;
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ CREATOR.writeToParcel(this, dest, flags);
+ }
+
+ public static final SafeParcelableCreatorAndWriter CREATOR = findCreator(ConnectionInfo.class);
+}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/GetServiceRequest.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/GetServiceRequest.java
index a203a99f..9df8735c 100644
--- a/play-services-basement/src/main/java/com/google/android/gms/common/internal/GetServiceRequest.java
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/GetServiceRequest.java
@@ -31,7 +31,7 @@ import java.util.Arrays;
public class GetServiceRequest extends AutoSafeParcelable {
@Field(1)
- private final int versionCode = 4;
+ private final int versionCode = 6;
@Field(2)
public final int serviceId;
@Field(3)
@@ -47,6 +47,7 @@ public class GetServiceRequest extends AutoSafeParcelable {
@Field(8)
public Account account;
@Field(9)
+ @Deprecated
private long field9;
@Field(10)
public Feature[] defaultFeatures;
@@ -59,7 +60,7 @@ public class GetServiceRequest extends AutoSafeParcelable {
@Field(14)
private boolean field14;
@Field(15)
- private String field15;
+ private String attributionTag;
private GetServiceRequest() {
serviceId = -1;
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/ValidateAccountRequest.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/ValidateAccountRequest.java
index 75e59d95..1cf0ecc1 100644
--- a/play-services-basement/src/main/java/com/google/android/gms/common/internal/ValidateAccountRequest.java
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/ValidateAccountRequest.java
@@ -16,8 +16,18 @@
package com.google.android.gms.common.internal;
-import org.microg.safeparcel.AutoSafeParcelable;
+import android.os.Parcel;
+import androidx.annotation.NonNull;
+import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
-public class ValidateAccountRequest extends AutoSafeParcelable {
- public static Creator CREATOR = new AutoCreator<>(ValidateAccountRequest.class);
+@SafeParcelable.Class
+public class ValidateAccountRequest extends AbstractSafeParcelable {
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ CREATOR.writeToParcel(this, dest, flags);
+ }
+
+ public static SafeParcelableCreatorAndWriter CREATOR = findCreator(ValidateAccountRequest.class);
}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/AbstractSafeParcelable.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/AbstractSafeParcelable.java
new file mode 100644
index 00000000..ec7d84d5
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/AbstractSafeParcelable.java
@@ -0,0 +1,24 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+public abstract class AbstractSafeParcelable implements SafeParcelable {
+
+ @SuppressWarnings("unchecked")
+ public static SafeParcelableCreatorAndWriter findCreator(java.lang.Class tClass) {
+ String creatorClassName = tClass.getName() + "$000Creator";
+ try {
+ return (SafeParcelableCreatorAndWriter) java.lang.Class.forName(creatorClassName).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("No Creator found for " + tClass.getName(), e);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelReader.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelReader.java
new file mode 100644
index 00000000..226f50e8
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelReader.java
@@ -0,0 +1,328 @@
+/*
+ * SPDX-FileCopyrightText: 2015, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+@SuppressWarnings("MagicNumber")
+public final class SafeParcelReader {
+
+ private SafeParcelReader() {
+ }
+
+ @Deprecated
+ public static int halfOf(int i) {
+ return i & 0xFFFF;
+ }
+
+ public static int getFieldId(int header) {
+ return header & 0xFFFF;
+ }
+
+ @Deprecated
+ public static int readSingleInt(Parcel parcel) {
+ return parcel.readInt();
+ }
+
+ public static int readHeader(Parcel parcel) {
+ return parcel.readInt();
+ }
+
+ private static int readSize(Parcel parcel, int header) {
+ if ((header & 0xFFFF0000) != 0xFFFF0000)
+ return header >> 16 & 0xFFFF;
+ return parcel.readInt();
+ }
+
+ private static void readExpectedSize(Parcel parcel, int header, int expectedSize) {
+ int i = readSize(parcel, header);
+ if (i != expectedSize)
+ throw new ReadException("Expected size " + expectedSize + " got " + i + " (0x" + Integer.toHexString(i) + ")", parcel);
+ }
+
+ @Deprecated
+ public static int readStart(Parcel parcel) {
+ return readObjectHeader(parcel);
+ }
+
+ public static int readObjectHeader(Parcel parcel) {
+ int header = readHeader(parcel);
+ int size = readSize(parcel, header);
+ int start = parcel.dataPosition();
+ if (getFieldId(header) != SafeParcelable.SAFE_PARCEL_OBJECT_MAGIC)
+ throw new ReadException("Expected object header. Got 0x" + Integer.toHexString(header), parcel);
+ int end = start + size;
+ if ((end < start) || (end > parcel.dataSize()))
+ throw new ReadException("Size read is invalid start=" + start + " end=" + end, parcel);
+ return end;
+ }
+
+ public static int readInt(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 4);
+ return parcel.readInt();
+ }
+
+ public static byte readByte(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 4);
+ return (byte) parcel.readInt();
+ }
+
+ public static short readShort(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 4);
+ return (short) parcel.readInt();
+ }
+
+ public static boolean readBool(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 4);
+ return parcel.readInt() != 0;
+ }
+
+ public static long readLong(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 8);
+ return parcel.readLong();
+ }
+
+ public static float readFloat(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 4);
+ return parcel.readFloat();
+ }
+
+ public static double readDouble(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 8);
+ return parcel.readDouble();
+ }
+
+ public static String readString(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ String string = parcel.readString();
+ parcel.setDataPosition(start + size);
+ return string;
+ }
+
+ public static IBinder readBinder(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ IBinder binder = parcel.readStrongBinder();
+ parcel.setDataPosition(start + size);
+ return binder;
+ }
+
+ public static T readParcelable(Parcel parcel, int header, Parcelable.Creator creator) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ T t = creator.createFromParcel(parcel);
+ parcel.setDataPosition(start + size);
+ return t;
+ }
+
+ public static ArrayList readList(Parcel parcel, int header, ClassLoader classLoader) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ ArrayList list = parcel.readArrayList(classLoader);
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static HashMap readMap(Parcel parcel, int header, ClassLoader classLoader) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ HashMap map = parcel.readHashMap(classLoader);
+ parcel.setDataPosition(start + size);
+ return map;
+ }
+
+ public static ArrayList readParcelableList(Parcel parcel, int header, Parcelable.Creator creator) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ ArrayList list = parcel.createTypedArrayList(creator);
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readStringList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ ArrayList list = parcel.createStringArrayList();
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readIntegerList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ ArrayList list = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ list.add(parcel.readInt());
+ }
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readLongList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ ArrayList list = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ list.add(parcel.readLong());
+ }
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readFloatList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ ArrayList list = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ list.add(parcel.readFloat());
+ }
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readDoubleList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ ArrayList list = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ list.add(parcel.readDouble());
+ }
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readBooleanList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ ArrayList list = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ list.add(parcel.readInt() != 0);
+ }
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static T[] readParcelableArray(Parcel parcel, int header, Parcelable.Creator creator) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ T[] arr = parcel.createTypedArray(creator);
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static String[] readStringArray(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ String[] arr = parcel.createStringArray();
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static byte[] readByteArray(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ byte[] arr = parcel.createByteArray();
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static byte[][] readByteArrayArray(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ byte[][] arr = new byte[length][];
+ for (int i = 0; i < length; i++) {
+ arr[i] = parcel.createByteArray();
+ }
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static float[] readFloatArray(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ float[] arr = parcel.createFloatArray();
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static int[] readIntArray(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int[] arr = parcel.createIntArray();
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static Bundle readBundle(Parcel parcel, int header, ClassLoader classLoader) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ Bundle bundle = parcel.readBundle(classLoader);
+ parcel.setDataPosition(start + size);
+ return bundle;
+ }
+
+ public static void skip(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ parcel.setDataPosition(parcel.dataPosition() + size);
+ }
+
+ public static class ReadException extends RuntimeException {
+ public ReadException(String message, Parcel parcel) {
+ super(message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelWriter.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelWriter.java
new file mode 100644
index 00000000..b2f96116
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelWriter.java
@@ -0,0 +1,384 @@
+/*
+ * SPDX-FileCopyrightText: 2015, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+import java.util.Map;
+
+@SuppressWarnings("MagicNumber")
+public final class SafeParcelWriter {
+
+ private SafeParcelWriter() {
+ }
+
+ private static void writeHeader(Parcel parcel, int fieldId, int size) {
+ if (size >= 0xFFFF) {
+ parcel.writeInt(0xFFFF0000 | fieldId);
+ parcel.writeInt(size);
+ } else {
+ parcel.writeInt(size << 16 | fieldId);
+ }
+ }
+
+ @Deprecated
+ public static int writeStart(Parcel parcel) {
+ return writeObjectHeader(parcel);
+ }
+
+ public static int writeObjectHeader(Parcel parcel) {
+ writeHeader(parcel, SafeParcelable.SAFE_PARCEL_OBJECT_MAGIC, 0xFFFF);
+ return parcel.dataPosition();
+ }
+
+ private static int writeObjectHeader(Parcel parcel, int fieldId) {
+ writeHeader(parcel, fieldId, 0xFFFF);
+ return parcel.dataPosition();
+ }
+
+ @Deprecated
+ public static void writeEnd(Parcel parcel, int start) {
+ finishObjectHeader(parcel, start);
+ }
+
+ public static void finishObjectHeader(Parcel parcel, int start) {
+ int end = parcel.dataPosition();
+ int length = end - start;
+ parcel.setDataPosition(start - 4);
+ parcel.writeInt(length);
+ parcel.setDataPosition(end);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Boolean val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 4);
+ parcel.writeInt(val ? 1 : 0);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Byte val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 4);
+ parcel.writeInt(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Short val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 4);
+ parcel.writeInt(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Integer val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 4);
+ parcel.writeInt(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Long val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 8);
+ parcel.writeLong(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Float val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 4);
+ parcel.writeFloat(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Double val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 8);
+ parcel.writeDouble(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, String val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeString(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, Parcelable val, int flags, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ val.writeToParcel(parcel, flags);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, Bundle val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeBundle(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, byte[] val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeByteArray(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, byte[][] val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.length);
+ for (byte[] arr : val) {
+ parcel.writeByteArray(arr);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, float[] val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeFloatArray(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, int[] val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeIntArray(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, String[] val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeStringArray(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeStringList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeStringList(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeIntegerList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (Integer i : val) {
+ parcel.writeInt(i);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeLongList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (Long l : val) {
+ parcel.writeLong(l);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeFloatList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (Float f : val) {
+ parcel.writeFloat(f);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeDoubleList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (Double d : val) {
+ parcel.writeDouble(d);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeBooleanList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (Boolean b : val) {
+ parcel.writeInt(b ? 1 : 0);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ private static void writeArrayPart(Parcel parcel, T val, int flags) {
+ int before = parcel.dataPosition();
+ parcel.writeInt(1);
+ int start = parcel.dataPosition();
+ val.writeToParcel(parcel, flags);
+ int end = parcel.dataPosition();
+ parcel.setDataPosition(before);
+ parcel.writeInt(end - start);
+ parcel.setDataPosition(end);
+ }
+
+ public static void write(Parcel parcel, int fieldId, T[] val, int flags, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.length);
+ for (T t : val) {
+ if (t == null) {
+ parcel.writeInt(0);
+ } else {
+ writeArrayPart(parcel, t, flags);
+ }
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, List val, int flags, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (T t : val) {
+ if (t == null) {
+ parcel.writeInt(0);
+ } else {
+ writeArrayPart(parcel, t, flags);
+ }
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, Parcel val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.appendFrom(val, 0, val.dataSize());
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeList(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, Map val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeMap(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, IBinder val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeStrongBinder(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelable.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelable.java
new file mode 100644
index 00000000..0d8d1cc0
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelable.java
@@ -0,0 +1,55 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+import android.os.Parcelable;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+public interface SafeParcelable extends Parcelable {
+ int SAFE_PARCEL_OBJECT_MAGIC = 0x4F45;
+
+ @Target(ElementType.TYPE)
+ @interface Class {
+ }
+
+ @Target(ElementType.CONSTRUCTOR)
+ @interface Constructor {
+
+ }
+
+ @Target(ElementType.PARAMETER)
+ @interface Param {
+ int value();
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.FIELD)
+ @interface Field {
+ int value();
+
+ boolean mayNull() default false;
+
+ java.lang.Class> subClass() default SafeParcelable.class;
+
+ boolean useValueParcel() default false;
+
+ boolean useDirectList() default false;
+
+ long versionCode() default -1;
+
+ String defaultValue() default "";
+
+ String type() default "";
+
+ String getterName() default "";
+
+ String getter() default "";
+ }
+}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableCreatorAndWriter.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableCreatorAndWriter.java
new file mode 100644
index 00000000..6afaa9c6
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableCreatorAndWriter.java
@@ -0,0 +1,13 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public interface SafeParcelableCreatorAndWriter extends Parcelable.Creator {
+ void writeToParcel(T object, Parcel parcel, int flags);
+}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableSerializer.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableSerializer.java
new file mode 100644
index 00000000..66b8b4d5
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableSerializer.java
@@ -0,0 +1,30 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class SafeParcelableSerializer {
+ public static T deserializeFromBytes(byte[] bytes, Parcelable.Creator tCreator) {
+ if (bytes == null) return null;
+ Parcel parcel = Parcel.obtain();
+ parcel.unmarshall(bytes, 0, bytes.length);
+ parcel.setDataPosition(0);
+ T parcelable = tCreator.createFromParcel(parcel);
+ parcel.recycle();
+ return parcelable;
+ }
+
+ public static byte[] serializeToBytes(T parcelable) {
+ if (parcelable == null) return null;
+ Parcel parcel = Parcel.obtain();
+ parcelable.writeToParcel(parcel, 0);
+ byte[] bytes = parcel.marshall();
+ parcel.recycle();
+ return bytes;
+ }
+}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/dynamic/ObjectWrapper.java b/play-services-basement/src/main/java/com/google/android/gms/dynamic/ObjectWrapper.java
index 649af71b..4bc96034 100644
--- a/play-services-basement/src/main/java/com/google/android/gms/dynamic/ObjectWrapper.java
+++ b/play-services-basement/src/main/java/com/google/android/gms/dynamic/ObjectWrapper.java
@@ -18,6 +18,7 @@ package com.google.android.gms.dynamic;
import android.os.IBinder;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.lang.reflect.Field;
@@ -34,37 +35,13 @@ public class ObjectWrapper extends IObjectWrapper.Stub {
if (obj == null) {
return null;
}
+
if (obj instanceof ObjectWrapper) {
- return ((ObjectWrapper) obj).t;
+ return ((ObjectWrapper>) obj).t;
}
+
IBinder binder = obj.asBinder();
- Field[] fields = binder.getClass().getDeclaredFields();
-
- if (fields.length < 1) {
- throw new IllegalArgumentException("No fields were found");
- }
-
- // Ignore synthetic field(s) from JaCoCo or elsewhere
- // https://www.jacoco.org/jacoco/trunk/doc/faq.html
-
- @Nullable
- Field field = null;
-
- for (Field currentField : fields) {
- if (currentField.isSynthetic()) {
- continue;
- }
-
- if (field == null) {
- field = currentField;
- } else {
- throw new IllegalArgumentException("Too many non-synthetic fields were found");
- }
- }
-
- if (field == null) {
- throw new IllegalArgumentException("No non-synthetic fields were found");
- }
+ Field field = getField(binder);
if (!field.isAccessible()) {
field.setAccessible(true);
@@ -85,6 +62,35 @@ public class ObjectWrapper extends IObjectWrapper.Stub {
}
}
+ @NonNull
+ private static Field getField(IBinder binder) {
+ Field[] fields = binder.getClass().getDeclaredFields();
+
+ if (fields.length < 1) {
+ throw new IllegalArgumentException("No fields were found");
+ }
+
+ @Nullable
+ Field field = null;
+
+ for (Field currentField : fields) {
+ if (currentField.isSynthetic()) {
+ continue;
+ }
+
+ if (field == null) {
+ field = currentField;
+ } else {
+ throw new IllegalArgumentException("Too many non-synthetic fields were found");
+ }
+ }
+
+ if (field == null) {
+ throw new IllegalArgumentException("No non-synthetic fields were found");
+ }
+ return field;
+ }
+
@Nullable
public static T unwrapTyped(IObjectWrapper obj, Class clazz) {
try {
@@ -95,6 +101,6 @@ public class ObjectWrapper extends IObjectWrapper.Stub {
}
public static ObjectWrapper wrap(T t) {
- return new ObjectWrapper(t);
+ return new ObjectWrapper<>(t);
}
-}
\ No newline at end of file
+}
diff --git a/play-services-basement/src/main/java/org/microg/gms/auth/AuthConstants.java b/play-services-basement/src/main/java/org/microg/gms/auth/AuthConstants.java
index 52c1dc72..6cac0d45 100644
--- a/play-services-basement/src/main/java/org/microg/gms/auth/AuthConstants.java
+++ b/play-services-basement/src/main/java/org/microg/gms/auth/AuthConstants.java
@@ -16,6 +16,8 @@
package org.microg.gms.auth;
+import org.microg.gms.basement.BuildConfig;
+
public class AuthConstants {
public static final String DEFAULT_ACCOUNT = "<>";
public static final String SCOPE_GET_ACCOUNT_ID = "^^_account_id_^^";
@@ -23,5 +25,5 @@ public class AuthConstants {
public static final String PROVIDER_METHOD_CLEAR_PASSWORD = "clear_password";
public static final String PROVIDER_EXTRA_CLEAR_PASSWORD = "clear_password";
public static final String PROVIDER_EXTRA_ACCOUNTS = "accounts";
- public static final String DEFAULT_ACCOUNT_TYPE = "com.mgoogle";
+ public static final String DEFAULT_ACCOUNT_TYPE = BuildConfig.BASE_PACKAGE_NAME;
}
diff --git a/play-services-basement/src/main/java/org/microg/gms/common/Constants.java b/play-services-basement/src/main/java/org/microg/gms/common/Constants.java
index 217ea437..a905f2bc 100644
--- a/play-services-basement/src/main/java/org/microg/gms/common/Constants.java
+++ b/play-services-basement/src/main/java/org/microg/gms/common/Constants.java
@@ -21,10 +21,8 @@ import org.microg.gms.basement.BuildConfig;
public class Constants {
public static final int GMS_VERSION_CODE = (BuildConfig.VERSION_CODE / 1000) * 1000;
public static final String GMS_PACKAGE_NAME = "com.google.android.gms";
- public static final String GSF_PACKAGE_NAME = "com.mgoogle.android.gsf";
+ public static final String GSF_PACKAGE_NAME = BuildConfig.BASE_PACKAGE_NAME + ".android.gsf";
public static final String GMS_PACKAGE_SIGNATURE_SHA1 = "38918a453d07199354f8b19af05ec6562ced5788";
- public static final String GMS_SECONDARY_PACKAGE_SIGNATURE_SHA1 = "bd32424203e0fb25f36b57e5aa356f9bdd1da998";
-
@Deprecated
public static final int MAX_REFERENCE_VERSION = GMS_VERSION_CODE;
}
diff --git a/play-services-basement/src/main/java/org/microg/gms/common/GmsService.java b/play-services-basement/src/main/java/org/microg/gms/common/GmsService.java
index c9b11ad1..efdbb1d2 100644
--- a/play-services-basement/src/main/java/org/microg/gms/common/GmsService.java
+++ b/play-services-basement/src/main/java/org/microg/gms/common/GmsService.java
@@ -19,15 +19,156 @@ package org.microg.gms.common;
public enum GmsService {
UNKNOWN(-2),
ANY(-1),
+ GAMES(1, "com.google.android.gms.games.service.START", "com.google.android.gms.games.internal.connect.service.START"),
+ PLUS(2, "com.google.android.gms.plus.service.START", "com.google.android.gms.plus.service.internal.START"),
+ PANORAMA(3, "com.google.android.gms.panorama.service.START"),
+ WALLET(4, "com.google.android.gms.wallet.service.BIND"),
PEOPLE(5, "com.google.android.gms.people.service.START"),
+ LOCATION(6),
+ APPSTATE(7, "com.google.android.gms.appstate.service.START"),
+ ADREQUEST(8, "com.google.android.gms.ads.service.START"),
ACCOUNT(9, "com.google.android.gms.accounts.ACCOUNT_SERVICE"),
+ CAST(10, "com.google.android.gms.cast.service.BIND_CAST_DEVICE_CONTROLLER_SERVICE"),
+ DRIVE(11, "com.google.android.gms.drive.ApiService.START"),
ADDRESS(12, "com.google.android.gms.identity.service.BIND"),
+ CAR(13, "com.google.android.gms.car.service.START"),
+ WEARABLE(14, "com.google.android.gms.wearable.BIND"),
AUTH_PROXY(16, "com.google.android.gms.auth.service.START"),
+ FITNESS(17, "com.google.android.gms.fitness.GoogleFitnessService.START"),
+ REMINDERS(18, "com.google.android.gms.reminders.service.START"),
+ LIGHTWEIGHT_INDEX(19, "com.google.android.gms.icing.LIGHTWEIGHT_INDEX_SERVICE"),
+ DEVICE_CONNECTION(20, "com.google.android.gms.deviceconnection.service.START"),
INDEX(21, "com.google.android.gms.icing.INDEX_SERVICE"),
+ LOCATION_REPORTING(22, "com.google.android.gms.location.reporting.service.START", "com.google.android.location.reporting.service.START"),
+ LOCATION_MANAGER(23, "com.google.android.location.internal.GoogleLocationManagerService.START"),
+ PLAY_LOG(24, "com.google.android.gms.playlog.service.START"),
+ DROIDGUARD(25, "com.google.android.gms.droidguard.service.START"),
+ LOCKBOX(26, "com.google.android.gms.lockbox.service.START"),
+ CAST_MIRRORING(27, "com.google.android.gms.cast_mirroring.service.START"),
+ NETWORK_QUALITY(28, "com.google.android.gms.mdm.services.START"),
+ FEEDBACK(29, "com.google.android.gms.feedback.internal.IFeedbackService"),
+ SEARCH_ADMINISTRATION(30),
+ PHOTO_AUTO_BACKUP(31, "com.google.android.gms.photos.autobackup.service.START"),
+ SEARCH_QUERIES(32),
+ SEARCH_GLOBAL(33),
+ UDC(35, "com.google.android.gms.udc.service.START"),
+ SEARCH_CORPORA(36),
+ DEVICE_MANAGER(37, "com.google.android.gms.mdm.services.DeviceManagerApiService.START"),
+ PSEUDONYMOUS_ID(38, "com.google.android.gms.pseudonymous.service.START"),
COMMON(39, "com.google.android.gms.common.service.START"),
+ CLEARCUT_LOGGER(40, "com.google.android.gms.clearcut.service.START"),
+ USAGE_REPORTING(41, "com.google.android.gms.usagereporting.service.START"),
+ KIDS(42, "com.google.android.gms.kids.service.START"),
+ DOWNLOAD(43, "com.google.android.gms.common.download.START"),
SIGN_IN(44, "com.google.android.gms.signin.service.START"),
+ SAFETY_NET_CLIENT(45, "com.google.android.gms.safetynet.service.START"),
+ GSERVICES(46, "com.google.android.gms.ads.gservice.START"),
+ CONTEXT_MANAGER(47, "com.google.android.contextmanager.service.ContextManagerService.START"),
+ AUDIO_MODEM(48, "com.google.android.gms.audiomodem.service.AudioModemService.START"),
+ NEARBY_SHARING(49, "com.google.android.gms.nearby.sharing.service.NearbySharingService.START"),
+ LIGHTWEIGHT_NETWORK_QUALITY(50, "com.google.android.gms.herrevad.services.LightweightNetworkQualityAndroidService.START"),
+ PHENOTYPE(51, "com.google.android.gms.phenotype.service.START"),
+ VOICE_UNLOCK(52, "com.google.android.gms.speech.service.START"),
+ NEARBY_CONNECTIONS(54, "com.google.android.gms.nearby.connection.service.START"),
+ FITNESS_SENSORS(55, "com.google.android.gms.fitness.SensorsApi"),
+ FITNESS_RECORDING(56, "com.google.android.gms.fitness.RecordingApi"),
+ FITNESS_HISTORY(57, "com.google.android.gms.fitness.HistoryApi"),
+ FITNESS_SESSIONS(58, "com.google.android.gms.fitness.SessionsApi"),
+ FITNESS_BLE(59, "com.google.android.gms.fitness.BleApi"),
+ FITNESS_CONFIG(60, "com.google.android.gms.fitness.ConfigApi"),
+ FITNESS_INTERNAL(61, "com.google.android.gms.fitness.InternalApi"),
+ NEARBY_MESSAGES(62, "com.google.android.gms.nearby.messages.service.NearbyMessagesService.START"),
+ HELP(63, "com.google.android.gms.googlehelp.service.GoogleHelpService.START"),
+ CONFIG(64, "com.google.android.gms.config.START"),
+ GEODATA(65, "com.google.android.gms.location.places.GeoDataApi"),
+ SEARCH_IME(66),
+ PLACE_DETECTION(67, "com.google.android.gms.location.places.PlaceDetectionApi"),
CREDENTIALS(68, "com.google.android.gms.auth.api.credentials.service.START"),
+ NEARBY_BOOTSTRAP(69, "com.google.android.gms.nearby.bootstrap.service.NearbyBootstrapService.START"),
+ PLUS_INTERNAL(70),
+ SOURCE_DEVICE(75, "com.google.android.gms.smartdevice.d2d.SourceDeviceService.START"),
+ TARGET_DEVICE(76, "com.google.android.gms.smartdevice.d2d.TargetDeviceService.START"),
+ APP_INVITE(77, "com.google.android.gms.appinvite.service.START"),
+ TAP_AND_PAY(79, "com.google.android.gms.tapandpay.service.BIND"),
+ CHROME_SYNC(80, "com.google.android.gms.chromesync.service.START"),
+ ACCOUNTS(81, "com.google.android.gms.smartdevice.setup.accounts.AccountsService.START"),
+ CAST_REMOTE_DISPLAY(83, "com.google.android.gms.cast.remote_display.service.START"),
+ TRUST_AGENT(85, "com.google.android.gms.trustagent.StateApi.START"),
+ AUTH_SIGN_IN(91, "com.google.android.gms.auth.api.signin.service.START"),
+ MEASUREMENT(93, "com.google.android.gms.measurement.START"),
+ FREIGHTER(98, "com.google.android.gms.freighter.service.START"),
+ GUNS(110, "com.google.android.gms.notifications.service.START"),
+ BLE(111, "com.google.android.gms.beacon.internal.IBleService.START"),
+ FIREBASE_AUTH(112, "com.google.firebase.auth.api.gms.service.START"),
+ APP_INDEXING(113),
+ GASS(116, "com.google.android.gms.gass.START"),
+ WORK_ACCOUNT(120),
+ INSTANT_APPS(121, "com.google.android.gms.instantapps.START"),
+ CAST_FIRSTPATY(122, "com.google.android.gms.cast.firstparty.START"),
+ AD_CACHE(123, "com.google.android.gms.ads.service.CACHE"),
+ SMS_RETRIEVER(126, "com.google.android.gms.auth.api.phone.service.SmsRetrieverApiService.START"),
+ CRYPT_AUTH(129, "com.google.android.gms.auth.cryptauth.cryptauthservice.START"),
+ DYNAMIC_LINKS(131, "com.google.firebase.dynamiclinks.service.START"),
+ FONTS(132, "com.google.android.gms.fonts.service.START"),
+ ROMANESCO(135, "com.google.android.gms.romanesco.service.START"),
+ TRAINER(139, "com.google.android.gms.learning.trainer.START"),
+ FIDO2_REGULAR(148, "com.google.android.gms.fido.fido2.regular.START"),
+ FIDO2_PRIVILEGED(149, "com.google.android.gms.fido.fido2.privileged.START"),
+ DATA_DOWNLOAD(152, "com.google.android.mdd.service.START"),
+ ACCOUNT_DATA(153, "com.google.android.gms.auth.account.data.service.START"),
+ CONSTELLATION(155, "com.google.android.gms.constellation.service.START"),
+ AUDIT(154, "com.google.android.gms.audit.service.START"),
+ SYSTEM_UPDATE(157, "com.google.android.gms.update.START_API_SERVICE"),
+ MOBSTORE(160, "com.google.android.mobstore.service.START"),
+ USER_LOCATION(163, "com.google.android.gms.userlocation.service.START"),
+ AD_HTTP(166, "com.google.android.gms.ads.service.HTTP"),
+ LANGUAGE_PROFILE(167, "com.google.android.gms.languageprofile.service.START"),
+ MDNS(168, "com.google.android.gms.mdns.service.START"),
+ FIDO2_ZEROPARTY(180, "com.google.android.gms.fido.fido2.zeroparty.START"),
+ G1_RESTORE(181, "com.google.android.gms.backup.G1_RESTORE"),
+ G1_BACKUP(182, "com.google.android.gms.backup.G1_BACKUP"),
+ OSS_LICENSES(185, "com.google.android.gms.oss.licenses.service.START"),
+ PAYSE(188, "com.google.android.gms.payse.service.BIND"),
+ RCS(189, "com.google.android.gms.rcs.START"),
+ CARRIER_AUTH(191, "com.google.android.gms.carrierauth.service.START"),
+ SYSTEM_UPDATE_SINGLE_UESR(192, "com.google.android.gms.update.START_SINGLE_USER_API_SERVICE"),
+ APP_USAGE(193, "com.google.android.gms.appusage.service.START"),
+ NEARBY_SHARING_2(194, "com.google.android.gms.nearby.sharing.START_SERVICE"),
+ AD_CONSENT_LOOKUP(195, "com.google.android.gms.ads.service.CONSENT_LOOKUP"),
+ CREDENTIAL_MANAGER(196, "com.google.android.gms.credential.manager.service.firstparty.START"),
+ PHONE_INTERNAL(197, "com.google.android.gms.auth.api.phone.service.InternalService.START"),
+ PAY(198, "com.google.android.gms.pay.service.BIND"),
+ ASTERISM(199, "com.google.android.gms.asterism.service.START"),
+ MODULE_RESTORE(201, "com.google.android.gms.backup.GMS_MODULE_RESTORE"),
+ FACS_CACHE(202, "com.google.android.gms.facs.cache.service.START"),
+ RECAPTCHA(205, "com.google.android.gms.recaptcha.service.START"),
+ CONTACT_SYNC(208, "com.google.android.gms.people.contactssync.service.START"),
IDENTITY_SIGN_IN(212, "com.google.android.gms.auth.api.identity.service.signin.START"),
+ CREDENTIAL_STORE(214, "com.google.android.gms.fido.credentialstore.internal_service.START"),
+ MDI_SYNC(215, "com.google.android.gms.mdisync.service.START"),
+ EVENT_ATTESTATION(216, "com.google.android.gms.ads.identifier.service.EVENT_ATTESTATION"),
+ SCHEDULER(218, "com.google.android.gms.scheduler.ACTION_PROXY_SCHEDULE"),
+ AUTHORIZATION(219, "com.google.android.gms.auth.api.identity.service.authorization.START"),
+ FACS_SYNC(220, "com.google.android.gms.facs.internal.service.START"),
+ AUTH_CONFIG_SYNC(221, "com.google.android.gms.auth.config.service.START"),
+ CREDENTIAL_SAVING(223, "com.google.android.gms.auth.api.identity.service.credentialsaving.START"),
+ GOOGLE_AUTH(224, "com.google.android.gms.auth.account.authapi.START"),
+ ENTERPRISE_LOADER(225, "com.google.android.gms.enterprise.loader.service.START"),
+ THUNDERBIRD(226, "com.google.android.gms.thunderbird.service.START"),
+ NEARBY_EXPOSURE(236, "com.google.android.gms.nearby.exposurenotification.START"),
+ GMS_COMPLIANCE(257, "com.google.android.gms.gmscompliance.service.START"),
+ FIDO_SOURCE_DEVICE(262, "com.google.android.gms.fido.sourcedevice.service.START"),
+ FAST_PAIR(265, "com.google.android.gms.nearby.fastpair.START"),
+ MATCHSTICK_LIGHTER(268, "com.google.android.gms.matchstick.lighter.service.START"),
+ FIDO_TARGET_DEVICE_INTERNAL(269, "com.google.android.gms.fido.targetdevice.internal_service.START"),
+ TELEMETRY(270, "com.google.android.gms.common.telemetry.service.START"),
+ SECOND_DEVICE_AUTH(275, "com.google.android.gms.setup.auth.SecondDeviceAuth.START"),
+ LOCATION_SHARING_REPORTER(277, "com.google.android.gms.locationsharingreporter.service.START"),
+ OCR(279, "com.google.android.gms.ocr.service.START"),
+ POTOKENS(285, "com.google.android.gms.potokens.service.START"),
+ OCR_INTERNAL(281, "com.google.android.gms.ocr.service.internal.START"),
+ IN_APP_REACH(315, "com.google.android.gms.inappreach.service.START"),
+ APP_ERRORS(334, "com.google.android.gms.apperrors.service.START_APP_ERROR"),
;
public int SERVICE_ID;
@@ -69,4 +210,4 @@ public enum GmsService {
if (this != UNKNOWN) return toString();
return "UNKNOWN(" + serviceId + ")";
}
-}
\ No newline at end of file
+}
diff --git a/play-services-basement/src/main/java/org/microg/gms/common/Hide.java b/play-services-basement/src/main/java/org/microg/gms/common/Hide.java
new file mode 100644
index 00000000..e15414b5
--- /dev/null
+++ b/play-services-basement/src/main/java/org/microg/gms/common/Hide.java
@@ -0,0 +1,19 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.common;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Hide the class, method or field from the public API.
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface Hide {
+}
diff --git a/play-services-basement/src/main/java/org/microg/gms/common/PublicApi.java b/play-services-basement/src/main/java/org/microg/gms/common/PublicApi.java
index 92663979..a7fb9b44 100644
--- a/play-services-basement/src/main/java/org/microg/gms/common/PublicApi.java
+++ b/play-services-basement/src/main/java/org/microg/gms/common/PublicApi.java
@@ -43,6 +43,8 @@ public @interface PublicApi {
* marked as public api.
*
* @return true if the method or field is not part of the public api
+ * @deprecated use {@link Hide} instead
*/
+ @Deprecated
boolean exclude() default false;
}
diff --git a/play-services-basement/src/main/java/org/microg/gms/gcm/GcmConstants.java b/play-services-basement/src/main/java/org/microg/gms/gcm/GcmConstants.java
index d96fe90a..00117d4e 100644
--- a/play-services-basement/src/main/java/org/microg/gms/gcm/GcmConstants.java
+++ b/play-services-basement/src/main/java/org/microg/gms/gcm/GcmConstants.java
@@ -16,29 +16,80 @@
package org.microg.gms.gcm;
+import org.microg.gms.basement.BuildConfig;
+
public final class GcmConstants {
- public static final String ACTION_C2DM_RECEIVE = "com.mgoogle.android.c2dm.intent.RECEIVE";
- public static final String ACTION_C2DM_REGISTER = "com.mgoogle.android.c2dm.intent.REGISTER";
- public static final String ACTION_C2DM_REGISTRATION = "com.mgoogle.android.c2dm.intent.REGISTRATION";
- public static final String ACTION_C2DM_UNREGISTER = "com.mgoogle.android.c2dm.intent.UNREGISTER";
+ public static final String ACTION_C2DM_RECEIVE = BuildConfig.BASE_PACKAGE_NAME + ".android.c2dm.intent.RECEIVE";
+ public static final String ACTION_C2DM_REGISTER = BuildConfig.BASE_PACKAGE_NAME + ".android.c2dm.intent.REGISTER";
+ public static final String ACTION_C2DM_REGISTRATION = BuildConfig.BASE_PACKAGE_NAME + ".android.c2dm.intent.REGISTRATION";
+ public static final String ACTION_C2DM_UNREGISTER = BuildConfig.BASE_PACKAGE_NAME + ".android.c2dm.intent.UNREGISTER";
+ public static final String ACTION_GCM_SEND = BuildConfig.BASE_PACKAGE_NAME + ".android.gcm.intent.SEND";
+ public static final String ACTION_NOTIFICATION_OPEN = BuildConfig.BASE_PACKAGE_NAME + ".android.gms.gcm.NOTIFICATION_OPEN";
+ public static final String ACTION_NOTIFICATION_DISMISS = BuildConfig.BASE_PACKAGE_NAME + ".android.gms.gcm.NOTIFICATION_DISMISS";
+ public static final String ACTION_SCHEDULE = BuildConfig.BASE_PACKAGE_NAME + ".android.gms.gcm.ACTION_SCHEDULE";
+ public static final String ACTION_TASK_READY = BuildConfig.BASE_PACKAGE_NAME + ".android.gms.gcm.ACTION_TASK_READY";
+ public static final String ACTION_TASK_INITIALZE = BuildConfig.BASE_PACKAGE_NAME + ".android.gms.gcm.SERVICE_ACTION_INITIALIZE";
+ public static final String ACTION_INSTANCE_ID = BuildConfig.BASE_PACKAGE_NAME + ".android.gms.iid.InstanceID";
public static final String EXTRA_APP = "app";
public static final String EXTRA_APP_OVERRIDE = "org.microg.gms.gcm.APP_OVERRIDE";
+ public static final String EXTRA_APP_ID = "appid";
+ public static final String EXTRA_APP_VERSION_CODE = "app_ver";
public static final String EXTRA_APP_VERSION_NAME = "app_ver_name";
+ public static final String EXTRA_CLIENT_VERSION = "cliv";
+ public static final String EXTRA_COMPONENT = "component";
public static final String EXTRA_COLLAPSE_KEY = "collapse_key";
+ public static final String EXTRA_DELAY = "google.delay";
public static final String EXTRA_DELETE = "delete";
public static final String EXTRA_ERROR = "error";
public static final String EXTRA_FROM = "from";
+ public static final String EXTRA_GSF_INTENT = "GSF";
+ public static final String EXTRA_GMS_VERSION = "gmsv";
+ public static final String EXTRA_IS_MESSENGER2 = "messenger2";
public static final String EXTRA_KID = "kid";
public static final String EXTRA_MESSENGER = "google.messenger";
+ public static final String EXTRA_MESSAGE_TYPE = "message_type";
public static final String EXTRA_MESSAGE_ID = "google.message_id";
+ public static final String EXTRA_OS_VERSION = "osv";
+ public static final String EXTRA_PENDING_INTENT = BuildConfig.BASE_PACKAGE_NAME + ".android.gms.gcm.PENDING_INTENT";
+ public static final String EXTRA_PUBLIC_KEY = "pub2";
+ public static final String EXTRA_RAWDATA = "rawData";
+ public static final String EXTRA_RAWDATA_BASE64 = "gcm.rawData64";
public static final String EXTRA_REGISTRATION_ID = "registration_id";
public static final String EXTRA_RETRY_AFTER = "Retry-After";
+ public static final String EXTRA_SCHEDULER_ACTION = "scheduler_action";
+ public static final String EXTRA_SCOPE = "scope";
public static final String EXTRA_SENDER = "sender";
+ public static final String EXTRA_SENDER_LEGACY = "legacy.sender";
public static final String EXTRA_SEND_TO = "google.to";
public static final String EXTRA_SEND_FROM = "google.from";
+ public static final String EXTRA_SIGNATURE = "sig";
+ public static final String EXTRA_SUBSCIPTION = "subscription";
+ public static final String EXTRA_SUBTYPE = "subtype";
+ public static final String EXTRA_USE_GSF = "useGsf";
+ public static final String EXTRA_TAG = "tag";
+ public static final String EXTRA_TOPIC = "gcm.topic";
public static final String EXTRA_TTL = "google.ttl";
public static final String EXTRA_UNREGISTERED = "unregistered";
+ public static final String MESSAGE_TYPE_GCM = "gcm";
+ public static final String MESSAGE_TYPE_DELETED_MESSAGE = "deleted_message";
+ public static final String MESSAGE_TYPE_SEND_ERROR = "send_error";
+ public static final String MESSAGE_TYPE_SEND_EVENT = "send_event";
+
+ public static final String SCHEDULER_ACTION_CANCEL = "CANCEL_TASK";
+ public static final String SCHEDULER_ACTION_CANCEL_ALL = "CANCEL_ALL";
+ public static final String SCHEDULER_ACTION_SCHEDULE = "SCHEDULE_TASK";
+
+ public static final String PERMISSION_GTALK = BuildConfig.BASE_PACKAGE_NAME + ".android.gtalkservice.permission.GTALK_SERVICE";
+ public static final String PERMISSION_NETWORK_TASK = BuildConfig.BASE_PACKAGE_NAME + ".android.gms.permission.BIND_NETWORK_TASK_SERVICE";
+ public static final String PERMISSION_RECEIVE = BuildConfig.BASE_PACKAGE_NAME + ".android.c2dm.permission.RECEIVE";
+ public static final String PERMISSION_SEND = BuildConfig.BASE_PACKAGE_NAME + ".android.c2dm.permission.SEND";
+
public static final String ERROR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";
+
+ public static final String INSTANCE_ID_SCOPE_GCM = "GCM";
+
+ public static final String GCMID_INSTANCE_ID = "google.com/iid";
+ public static final String GCMID_REFRESH = "gcm.googleapis.com/refresh";
}
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 a1232546..22e0b42c 100644
--- a/play-services-core/build.gradle
+++ b/play-services-core/build.gradle
@@ -23,6 +23,8 @@ dependencies {
implementation "de.hdodenhof:circleimageview:$circleimageviewVersion"
implementation "androidx.webkit:webkit:$webkitVersion"
+ implementation project(':fake-signature')
+
implementation project(':play-services-base-core')
implementation project(':play-services-core-proto')
implementation project(':play-services-core:microg-ui-tools') // deprecated
@@ -47,21 +49,41 @@ dependencies {
}
android {
+ namespace "${basePackageName}.android.gms"
+
compileSdkVersion androidCompileSdk
buildToolsVersion androidBuildVersionTools
defaultConfig {
versionName version
versionCode appVersionCode
- resConfigs 'xxhdpi'
+ resourceConfigurations += ['xxhdpi']
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
+ buildConfigField "String", "BASE_PACKAGE_NAME", "\"$basePackageName\""
+
+ multiDexEnabled true
+ multiDexKeepProguard file('multidex-keep.pro')
+
ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
}
+ buildConfigField "String", "APPLICATION_NAMESPACE", "\"${android.namespace}\""
+ buildConfigField "String", "BASE_PACKAGE_NAME", "\"$basePackageName\""
+ manifestPlaceholders = [
+ basePackageName: "$basePackageName"
+ ]
+
+ // provide package name to xml resources
+ resValue "string", "var_authenticator_account_type", "$basePackageName"
+ resValue "string", "var_contact_syncadapter_account_type", "$basePackageName"
+ resValue "string", "var_pref_auth_action_security_settings", "${basePackageName}.android.gms.accountsettings.SECURITY_SETTINGS"
+ resValue "string", "var_pref_auth_action_privacy_settings", "${basePackageName}.android.gms.accountsettings.PRIVACY_SETTINGS"
+ resValue "string", "var_pref_auth_action_preferences_settings", "${basePackageName}.android.gms.accountsettings.ACCOUNT_PREFERENCES_SETTINGS"
+ resValue "string", "var_pref_start_gms_package", "${basePackageName}.android.gms"
}
buildFeatures {
@@ -76,7 +98,7 @@ android {
}
lintOptions {
- disable 'MissingTranslation', 'BatteryLife', 'ImpliedQuantity', 'MissingQuantity', 'InvalidWakeLockTag', 'Range'
+ disable 'MissingTranslation', 'GetLocales', 'BatteryLife', 'ImpliedQuantity', 'MissingQuantity', 'InvalidWakeLockTag', 'Range'
}
buildTypes {
@@ -87,14 +109,14 @@ android {
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
}
packagingOptions {
exclude 'META-INF/ASL2.0'
jniLibs {
- useLegacyPackaging false
+ useLegacyPackaging true
}
}
}
diff --git a/play-services-core/microg-ui-tools/build.gradle b/play-services-core/microg-ui-tools/build.gradle
index d0dbd48f..260aa6a5 100644
--- a/play-services-core/microg-ui-tools/build.gradle
+++ b/play-services-core/microg-ui-tools/build.gradle
@@ -23,17 +23,20 @@ android {
defaultConfig {
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
+
+ buildConfigField "String", "GMS_APPLICATION_NAMESPACE", "\"$applicationNamespace\""
}
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'
+ 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-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/java/org/microg/tools/ui/SwitchBar.java b/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBar.java
index 0a30f683..b9144222 100644
--- a/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBar.java
+++ b/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBar.java
@@ -116,12 +116,39 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
mSwitch.setChecked(checked);
}
+ public void setCheckedInternal(boolean checked) {
+ setTextViewLabel(checked);
+ mSwitch.setCheckedInternal(checked);
+ }
+
+ public boolean isChecked() {
+ return mSwitch.isChecked();
+ }
+
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
mTextView.setEnabled(enabled);
mSwitch.setEnabled(enabled);
}
+ public final ToggleSwitch getSwitch() {
+ return mSwitch;
+ }
+
+ public void show() {
+ if (!isShowing()) {
+ setVisibility(View.VISIBLE);
+ mSwitch.setOnCheckedChangeListener(this);
+ }
+ }
+
+ public void hide() {
+ if (isShowing()) {
+ setVisibility(View.GONE);
+ mSwitch.setOnCheckedChangeListener(null);
+ }
+ }
+
public boolean isShowing() {
return (getVisibility() == View.VISIBLE);
}
@@ -151,6 +178,13 @@ public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedC
mSwitchChangeListeners.add(listener);
}
+ public void removeOnSwitchChangeListener(OnSwitchChangeListener listener) {
+ if (!mSwitchChangeListeners.contains(listener)) {
+ throw new IllegalStateException("Cannot remove OnSwitchChangeListener");
+ }
+ mSwitchChangeListeners.remove(listener);
+ }
+
static class SavedState extends BaseSavedState {
boolean checked;
boolean visible;
diff --git a/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBarResourceSettingsFragment.java b/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBarResourceSettingsFragment.java
index c6cadb2f..f590aa25 100644
--- a/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBarResourceSettingsFragment.java
+++ b/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBarResourceSettingsFragment.java
@@ -21,30 +21,27 @@ import android.os.Bundle;
import com.google.android.material.switchmaterial.SwitchMaterial;
public abstract class SwitchBarResourceSettingsFragment extends ResourceSettingsFragment implements SwitchBar.OnSwitchChangeListener {
- protected SwitchBar switchBar;
- private SwitchMaterial switchMaterial;
+ private final SwitchMaterial switchMaterial;
private boolean listenerSetup = false;
+ protected SwitchBarResourceSettingsFragment(SwitchMaterial switchMaterial) {
+ this.switchMaterial = switchMaterial;
+ }
+
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
-
-// switchBar = activity.getSwitchBar();
-// switchBar.show();
-// switchMaterial = switchBar.getSwitch();
}
@Override
public void onDestroyView() {
super.onDestroyView();
-// switchBar.hide();
}
@Override
public void onResume() {
super.onResume();
if (!listenerSetup) {
-// switchBar.addOnSwitchChangeListener(this);
listenerSetup = true;
}
}
@@ -52,7 +49,6 @@ public abstract class SwitchBarResourceSettingsFragment extends ResourceSettings
@Override
public void onPause() {
if (listenerSetup) {
-// switchBar.removeOnSwitchChangeListener(this);
listenerSetup = false;
}
super.onPause();
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">
+
+
+
diff --git a/play-services-core/multidex-keep.pro b/play-services-core/multidex-keep.pro
new file mode 100644
index 00000000..0cd8699e
--- /dev/null
+++ b/play-services-core/multidex-keep.pro
@@ -0,0 +1,9 @@
+# Make sure maps is in the primary dex file
+-keep class com.google.android.gms.maps.** { *; }
+-keep class org.microg.gms.maps.** { *; }
+-keep class com.mapbox.** { *; }
+-keep class org.oscim.** { *; }
+
+# Keep Conscrypt in the primary dex file otherwise it will error out on legacy Android versions
+-keep class com.google.android.gms.common.security.ProviderInstallerImpl { *; }
+-keep class com.google.android.gms.org.conscrypt.** { *; }
diff --git a/play-services-core/proguard-rules.pro b/play-services-core/proguard-rules.pro
index 9b421ddd..923a7661 100644
--- a/play-services-core/proguard-rules.pro
+++ b/play-services-core/proguard-rules.pro
@@ -21,10 +21,13 @@
# Keep dynamically loaded GMS classes
-keep public class com.google.android.gms.common.security.ProviderInstallerImpl { public *; }
+-keep public class com.google.android.gms.dynamic.IObjectWrapper { public *; }
+-keep public class com.google.android.gms.dynamite.descriptors.** { public *; }
# Keep AutoSafeParcelables
-keep public class * extends org.microg.safeparcel.AutoSafeParcelable {
@org.microg.safeparcel.SafeParceled *;
+ (...);
}
# Keep form data
diff --git a/play-services-core/src/main/AndroidManifest.xml b/play-services-core/src/main/AndroidManifest.xml
index 0cbed7c6..5a42409c 100644
--- a/play-services-core/src/main/AndroidManifest.xml
+++ b/play-services-core/src/main/AndroidManifest.xml
@@ -15,42 +15,48 @@
~ limitations under the License.
-->
+ xmlns:tools="http://schemas.android.com/tools">
+
-
+
@@ -59,15 +65,17 @@
+
-
-
-
+
+
+
-
+
@@ -86,42 +94,41 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:multiArch="true"
- android:theme="@style/AppTheme"
- android:networkSecurityConfig="@xml/network_security_config">
+ android:theme="@style/Theme.App"
+ android:networkSecurityConfig="@xml/network_security_config"
+ tools:targetApi="r">
-
-
-
+
+ android:exported="true" />
-
+
-
+
@@ -132,15 +139,16 @@
-
+
+
@@ -148,10 +156,11 @@
-
-
+
+
@@ -159,9 +168,10 @@
-
+
@@ -171,6 +181,7 @@
@@ -183,6 +194,7 @@
@@ -206,6 +218,7 @@
@@ -218,12 +231,13 @@
-
+
-
+
+ android:process=":ui"
+ android:theme="@style/Theme.LoginBlue.Base">
@@ -248,7 +263,7 @@
@@ -270,11 +285,12 @@
@@ -282,19 +298,22 @@
-
+
-
+
-
+
@@ -302,7 +321,8 @@
@@ -333,10 +353,11 @@
@@ -354,6 +375,15 @@
android:resource="@string/gms_settings_summary" />
+
+
+
+
+ android:taskAffinity="org.microg.gms.settings" />
+
+
+
-
+
+
+
+
+
+
+
+
+
-
+
-
+
diff --git a/play-services-core/src/main/java/com/google/android/gms/chimera/DynamiteModuleInitializer.java b/play-services-core/src/main/java/com/google/android/gms/chimera/DynamiteModuleInitializer.java
new file mode 100644
index 00000000..3605e8ac
--- /dev/null
+++ b/play-services-core/src/main/java/com/google/android/gms/chimera/DynamiteModuleInitializer.java
@@ -0,0 +1,25 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.chimera;
+
+import android.annotation.SuppressLint;
+import android.util.Log;
+import androidx.annotation.Keep;
+
+import android.content.Context;
+
+@Keep
+public class DynamiteModuleInitializer {
+ private static final String TAG = "DynamiteModule";
+
+ public static void initializeModuleV1(Context context) {
+ initializeModuleV2(context, "com.google.android.gms".equals(context.getPackageName()));
+ }
+
+ public static void initializeModuleV2(Context context, boolean withGmsPackage) {
+ Log.d(TAG, "initializeModuleV2 context: " + context + ", withGmsPackage: " + withGmsPackage);
+ }
+}
diff --git a/play-services-core/src/main/java/com/google/android/gms/common/GoogleCertificatesImpl.java b/play-services-core/src/main/java/com/google/android/gms/common/GoogleCertificatesImpl.java
deleted file mode 100644
index 7ab30bc3..00000000
--- a/play-services-core/src/main/java/com/google/android/gms/common/GoogleCertificatesImpl.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2019 microG Project Team
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.gms.common;
-
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-import android.util.Log;
-
-import androidx.annotation.Keep;
-
-import com.google.android.gms.common.internal.GoogleCertificatesQuery;
-import com.google.android.gms.common.internal.IGoogleCertificatesApi;
-import com.google.android.gms.dynamic.IObjectWrapper;
-import com.google.android.gms.dynamic.ObjectWrapper;
-
-import org.microg.gms.common.PackageUtils;
-
-@Keep
-public class GoogleCertificatesImpl extends IGoogleCertificatesApi.Stub {
- private static final String TAG = "GmsCertImpl";
-
- @Override
- public IObjectWrapper getGoogleCertficates() throws RemoteException {
- Log.d(TAG, "unimplemented Method: getGoogleCertficates");
- return null;
- }
-
- @Override
- public IObjectWrapper getGoogleReleaseCertificates() throws RemoteException {
- Log.d(TAG, "unimplemented Method: getGoogleReleaseCertificates");
- return null;
- }
-
- @Override
- public boolean isGoogleReleaseSigned(String packageName, IObjectWrapper certData) throws RemoteException {
- return PackageUtils.isGooglePackage(packageName, ObjectWrapper.unwrapTyped(certData, byte[].class));
- }
-
- @Override
- public boolean isGoogleSigned(String packageName, IObjectWrapper certData) throws RemoteException {
- return PackageUtils.isGooglePackage(packageName, ObjectWrapper.unwrapTyped(certData, byte[].class));
- }
-
- @Override
- public boolean isGoogleOrPlatformSigned(GoogleCertificatesQuery query, IObjectWrapper packageManager) throws RemoteException {
- PackageManager pm = ObjectWrapper.unwrapTyped(packageManager, PackageManager.class);
- if (query == null || query.getPackageName() == null) {
- return false;
- } else if (query.getCertData() == null) {
- if (pm == null) return false;
- return PackageUtils.isGooglePackage(pm, query.getPackageName());
- } else {
- return PackageUtils.isGooglePackage(query.getPackageName(), query.getCertData().getBytes());
- }
- }
-}
diff --git a/play-services-core/src/main/java/com/google/android/gms/common/security/ProviderInstallerImpl.java b/play-services-core/src/main/java/com/google/android/gms/common/security/ProviderInstallerImpl.java
index e25391e5..0270e626 100644
--- a/play-services-core/src/main/java/com/google/android/gms/common/security/ProviderInstallerImpl.java
+++ b/play-services-core/src/main/java/com/google/android/gms/common/security/ProviderInstallerImpl.java
@@ -5,11 +5,12 @@
package com.google.android.gms.common.security;
+import static android.os.Build.VERSION.SDK_INT;
import static com.google.android.gms.security.ProviderInstaller.PROVIDER_NAME;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.os.Build;
import android.os.Process;
import android.util.Log;
@@ -53,13 +54,14 @@ public class ProviderInstallerImpl {
String packageName = PackageUtils.packageFromProcessId(context, Process.myPid());
if (packageName != null && packageName.contains(".")) return packageName;
try {
+ @SuppressLint("DiscouragedPrivateApi")
Method getBasePackageName = Context.class.getDeclaredMethod("getBasePackageName");
packageName = (String) getBasePackageName.invoke(context);
if (packageName != null) return packageName;
- } catch (Exception e) {
+ } catch (Exception ignored) {
}
- if (Build.VERSION.SDK_INT >= 29) {
+ if (SDK_INT >= 29) {
return context.getOpPackageName();
}
Context applicationContext = context.getApplicationContext();
diff --git a/play-services-core/src/main/java/org/microg/gms/auth/AccountContentProvider.java b/play-services-core/src/main/java/org/microg/gms/auth/AccountContentProvider.java
index 9c96646b..9274f439 100644
--- a/play-services-core/src/main/java/org/microg/gms/auth/AccountContentProvider.java
+++ b/play-services-core/src/main/java/org/microg/gms/auth/AccountContentProvider.java
@@ -17,6 +17,7 @@
package org.microg.gms.auth;
import static android.accounts.AccountManager.VISIBILITY_VISIBLE;
+import static android.os.Build.VERSION.SDK_INT;
import android.Manifest;
import android.accounts.Account;
@@ -27,7 +28,6 @@ import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
import android.util.Log;
@@ -36,6 +36,7 @@ import androidx.annotation.Nullable;
import org.microg.gms.common.PackageUtils;
import java.util.Arrays;
+import java.util.Objects;
import static org.microg.gms.auth.AuthConstants.DEFAULT_ACCOUNT_TYPE;
import static org.microg.gms.auth.AuthConstants.PROVIDER_EXTRA_ACCOUNTS;
@@ -54,11 +55,10 @@ public class AccountContentProvider extends ContentProvider {
@Nullable
@Override
public Bundle call(String method, String arg, Bundle extras) {
- String suggestedPackageName;
- suggestedPackageName = getCallingPackage();
+ String suggestedPackageName = getCallingPackage();
String packageName = PackageUtils.getAndCheckCallingPackage(getContext(), suggestedPackageName);
Log.d(TAG, "Call " + method + " from " + packageName + " with arg " + arg);
- if (!PackageUtils.callerHasExtendedAccess(getContext())) {
+ if (!PackageUtils.callerHasExtendedAccess(Objects.requireNonNull(getContext()))) {
String[] packagesForUid = getContext().getPackageManager().getPackagesForUid(Binder.getCallingUid());
if (packagesForUid != null && packagesForUid.length != 0)
Log.w(TAG, "Not granting extended access to " + Arrays.toString(packagesForUid)
@@ -72,10 +72,10 @@ public class AccountContentProvider extends ContentProvider {
if (arg != null && (arg.equals(DEFAULT_ACCOUNT_TYPE) || arg.startsWith(DEFAULT_ACCOUNT_TYPE + "."))) {
AccountManager am = AccountManager.get(getContext());
accounts = am.getAccountsByTypeForPackage(arg, packageName);
- if (accounts == null || accounts.length == 0) {
+ if (accounts.length == 0) {
accounts = am.getAccountsByType(arg);
}
- if (Build.VERSION.SDK_INT >= 26 && accounts != null && arg.equals(DEFAULT_ACCOUNT_TYPE)) {
+ if (SDK_INT >= 26 && arg.equals(DEFAULT_ACCOUNT_TYPE)) {
for (Account account : accounts) {
if (am.getAccountVisibility(account, packageName) == AccountManager.VISIBILITY_UNDEFINED) {
Log.d(TAG, "Make account " + account + " visible to " + packageName);
diff --git a/play-services-core/src/main/java/org/microg/gms/auth/AuthManager.java b/play-services-core/src/main/java/org/microg/gms/auth/AuthManager.java
index 73adeabf..57b6a516 100644
--- a/play-services-core/src/main/java/org/microg/gms/auth/AuthManager.java
+++ b/play-services-core/src/main/java/org/microg/gms/auth/AuthManager.java
@@ -18,24 +18,25 @@ package org.microg.gms.auth;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+import static android.os.Build.VERSION.SDK_INT;
import static org.microg.gms.auth.AuthPrefs.isTrustGooglePermitted;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.os.Build;
import android.util.Log;
+import org.microg.gms.base.core.BuildConfig;
import org.microg.gms.common.PackageUtils;
-import org.microg.mgms.settings.SettingsContract;
+import org.microg.gms.settings.SettingsContract;
import java.io.IOException;
public class AuthManager {
private static final String TAG = "GmsAuthManager";
- public static final String PERMISSION_TREE_BASE = "com.mgoogle.android.googleapps.permission.GOOGLE_AUTH.";
+ public static final String PERMISSION_TREE_BASE = BuildConfig.BASE_PACKAGE_NAME + ".android.googleapps.permission.GOOGLE_AUTH.";
public static final String PREF_AUTH_VISIBLE = SettingsContract.Auth.VISIBLE;
public static final int ONE_HOUR_IN_SECONDS = 60 * 60;
@@ -104,7 +105,7 @@ public class AuthManager {
public void setPermitted(boolean value) {
setUserData(buildPermKey(), value ? "1" : "0");
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && value && packageName != null) {
+ if (SDK_INT >= 26 && value && packageName != null) {
// Make account persistently visible as we already granted access
accountManager.setAccountVisibility(getAccount(), packageName, AccountManager.VISIBILITY_VISIBLE);
}
@@ -169,7 +170,7 @@ public class AuthManager {
public void setAuthToken(String service, String auth) {
getAccountManager().setAuthToken(getAccount(), buildTokenKey(service), auth);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && packageName != null && auth != null) {
+ if (SDK_INT >= 26 && packageName != null && auth != null) {
// Make account persistently visible as we already granted access
accountManager.setAccountVisibility(getAccount(), packageName, AccountManager.VISIBILITY_VISIBLE);
}
diff --git a/play-services-core/src/main/java/org/microg/gms/auth/AuthManagerServiceImpl.java b/play-services-core/src/main/java/org/microg/gms/auth/AuthManagerServiceImpl.java
index 622ff4a0..7f57a370 100644
--- a/play-services-core/src/main/java/org/microg/gms/auth/AuthManagerServiceImpl.java
+++ b/play-services-core/src/main/java/org/microg/gms/auth/AuthManagerServiceImpl.java
@@ -18,8 +18,6 @@ package org.microg.gms.auth;
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
import android.annotation.SuppressLint;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -40,7 +38,7 @@ import com.google.android.gms.auth.AccountChangeEventsRequest;
import com.google.android.gms.auth.AccountChangeEventsResponse;
import com.google.android.gms.auth.GetHubTokenInternalResponse;
import com.google.android.gms.auth.GetHubTokenRequest;
-import com.google.android.gms.auth.HasCababilitiesRequest;
+import com.google.android.gms.auth.HasCapabilitiesRequest;
import com.google.android.gms.auth.TokenData;
import com.google.android.gms.common.api.Scope;
@@ -52,11 +50,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
-import static android.accounts.AccountManager.KEY_ACCOUNTS;
-import static android.accounts.AccountManager.KEY_ACCOUNT_NAME;
-import static android.accounts.AccountManager.KEY_ACCOUNT_TYPE;
-import static android.accounts.AccountManager.KEY_AUTHTOKEN;
-import static android.accounts.AccountManager.KEY_CALLER_PID;
+import static android.accounts.AccountManager.*;
+import static android.os.Build.VERSION.SDK_INT;
public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
private static final String TAG = "GmsAuthManagerSvc";
@@ -72,6 +67,8 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
public static final String KEY_REQUEST_VISIBLE_ACTIVITIES = "request_visible_actions";
public static final String KEY_SUPPRESS_PROGRESS_SCREEN = "suppressProgressScreen";
public static final String KEY_SYNC_EXTRAS = "sync_extras";
+ public static final String KEY_DELEGATION_TYPE = "delegation_type";
+ public static final String KEY_DELEGATEE_USER_ID = "delegatee_user_id";
public static final String KEY_ERROR = "Error";
public static final String KEY_USER_RECOVERY_INTENT = "userRecoveryIntent";
@@ -118,7 +115,8 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
packageName = PackageUtils.getAndCheckCallingPackage(context, packageName, extras.getInt(KEY_CALLER_UID, 0), extras.getInt(KEY_CALLER_PID, 0));
boolean notify = extras.getBoolean(KEY_HANDLE_NOTIFICATION, false);
- Log.d(TAG, "getToken: account:" + account.name + " scope:" + scope + " extras:" + extras + ", notify: " + notify);
+ if (!AuthConstants.SCOPE_GET_ACCOUNT_ID.equals(scope))
+ Log.d(TAG, "getToken: account:" + account.name + " scope:" + scope + " extras:" + extras + ", notify: " + notify);
/*
* TODO: This scope seems to be invalid (according to https://developers.google.com/oauthplayground/),
@@ -126,6 +124,7 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
*/
scope = scope.replace("https://www.googleapis.com/auth/identity.plus.page.impersonation ", "");
+ assert packageName != null;
AuthManager authManager = new AuthManager(context, account.name, packageName, scope);
Bundle result = new Bundle();
result.putString(KEY_ACCOUNT_NAME, account.name);
@@ -180,12 +179,22 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
@Override
public Bundle requestGoogleAccountsAccess(String packageName) throws RemoteException {
- Log.w(TAG, "Not implemented: requestGoogleAccountsAccess(" + packageName + ")");
+ PackageUtils.assertExtendedAccess(context);
+ if (SDK_INT >= 26) {
+ for (Account account : get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)) {
+ AccountManager.get(context).setAccountVisibility(account, packageName, VISIBILITY_VISIBLE);
+ }
+ Bundle res = new Bundle();
+ res.putString("Error", "Ok");
+ return res;
+ } else {
+ Log.w(TAG, "Not implemented: requestGoogleAccountsAccess(" + packageName + ")");
+ }
return null;
}
@Override
- public int hasCapabilities(HasCababilitiesRequest request) throws RemoteException {
+ public int hasCapabilities(HasCapabilitiesRequest request) throws RemoteException {
Log.w(TAG, "Not implemented: hasCapabilities(" + request.account + ", " + Arrays.toString(request.capabilities) + ")");
return 1;
}
@@ -205,7 +214,11 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
Log.d(TAG, "clearToken: token:" + token + " extras:" + extras);
AccountManager.get(context).invalidateAuthToken(AuthConstants.DEFAULT_ACCOUNT_TYPE, token);
- return null;
+
+ Bundle res = new Bundle();
+ res.putString("Error", "Ok");
+ res.putBoolean("booleanResult", true);
+ return res;
}
@Override
diff --git a/play-services-core/src/main/java/org/microg/gms/auth/AuthRequest.java b/play-services-core/src/main/java/org/microg/gms/auth/AuthRequest.java
index 55ff536b..e1b4749a 100644
--- a/play-services-core/src/main/java/org/microg/gms/auth/AuthRequest.java
+++ b/play-services-core/src/main/java/org/microg/gms/auth/AuthRequest.java
@@ -113,7 +113,9 @@ public class AuthRequest extends HttpFormClient.Request {
public AuthRequest fromContext(Context context) {
build(context);
locale(Utils.getLocale(context));
- androidIdHex = Long.toHexString(LastCheckinInfo.read(context).getAndroidId());
+ if (AuthPrefs.shouldIncludeAndroidId(context)) {
+ androidIdHex = Long.toHexString(LastCheckinInfo.read(context).getAndroidId());
+ }
return this;
}
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 095496b0..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;
@@ -283,6 +283,10 @@ public class LoginActivity extends AssistantActivity {
webView.loadUrl(buildUrl(tmpl, Utils.getLocale(this)));
}
+ protected void runScript(String js) {
+ runOnUiThread(() -> webView.loadUrl("javascript:" + js));
+ }
+
private void closeWeb(boolean programmaticAuth) {
setMessage(R.string.auth_finalize);
runOnUiThread(() -> webView.setVisibility(INVISIBLE));
@@ -418,12 +422,32 @@ public class LoginActivity extends AssistantActivity {
Log.d(TAG, "JSBridge: addAccount");
}
+ @JavascriptInterface
+ public final void attemptLogin(String accountName, String password) {
+ Log.d(TAG, "JSBridge: attemptLogin");
+ }
+
+ @JavascriptInterface
+ public void backupSyncOptIn(String accountName) {
+ Log.d(TAG, "JSBridge: backupSyncOptIn");
+ }
+
+ @JavascriptInterface
+ public void clearOldLoginAttempts() {
+ Log.d(TAG, "JSBridge: clearOldLoginAttempts");
+ }
+
@JavascriptInterface
public final void closeView() {
Log.d(TAG, "JSBridge: closeView");
closeWeb(false);
}
+ @JavascriptInterface
+ public void fetchIIDToken(String entity) {
+ Log.d(TAG, "JSBridge: fetchIIDToken");
+ }
+
@JavascriptInterface
public final String fetchVerifiedPhoneNumber() {
Log.d(TAG, "JSBridge: fetchVerifiedPhoneNumber");
@@ -458,12 +482,17 @@ public class LoginActivity extends AssistantActivity {
@JavascriptInterface
public final int getAuthModuleVersionCode() {
- return 1;
+ return GMS_VERSION_CODE;
}
@JavascriptInterface
public final int getBuildVersionSdk() {
- return SDK_INT;
+ return Build.VERSION.SDK_INT;
+ }
+
+ @JavascriptInterface
+ public int getDeviceContactsCount() {
+ return -1;
}
@JavascriptInterface
@@ -537,15 +566,40 @@ public class LoginActivity extends AssistantActivity {
}
@JavascriptInterface
- public final void setAccountIdentifier(String accountIdentifier) {
+ public final void setAccountIdentifier(String accountName) {
Log.d(TAG, "JSBridge: setAccountIdentifier");
}
+ @JavascriptInterface
+ public void setAllActionsEnabled(boolean z) {
+ Log.d(TAG, "JSBridge: setAllActionsEnabled");
+ }
+
@JavascriptInterface
public final void setNewAccountCreated() {
Log.d(TAG, "JSBridge: setNewAccountCreated");
}
+ @JavascriptInterface
+ public void setPrimaryActionEnabled(boolean z) {
+ Log.d(TAG, "JSBridge: setPrimaryActionEnabled");
+ }
+
+ @JavascriptInterface
+ public void setPrimaryActionLabel(String str, int i) {
+ Log.d(TAG, "JSBridge: setPrimaryActionLabel: " + str);
+ }
+
+ @JavascriptInterface
+ public void setSecondaryActionEnabled(boolean z) {
+ Log.d(TAG, "JSBridge: setSecondaryActionEnabled");
+ }
+
+ @JavascriptInterface
+ public void setSecondaryActionLabel(String str, int i) {
+ Log.d(TAG, "JSBridge: setSecondaryActionLabel: " + str);
+ }
+
@JavascriptInterface
public final void showKeyboard() {
inputMethodManager.showSoftInput(webView, SHOW_IMPLICIT);
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;
}
diff --git a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinClient.java b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinClient.java
index 98598a09..df7c245b 100755
--- a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinClient.java
+++ b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinClient.java
@@ -80,8 +80,7 @@ public class CheckinClient {
DeviceIdentifier deviceIdent, PhoneInfo phoneInfo,
LastCheckinInfo checkinInfo, Locale locale,
List accounts, Boolean brandSpoof) {
- CheckinRequest.Builder builder;
- builder = new CheckinRequest.Builder()
+ CheckinRequest.Builder builder = new CheckinRequest.Builder()
.accountCookie(new ArrayList<>())
.androidId(checkinInfo.getAndroidId())
.checkin(new CheckinRequest.Checkin.Builder()
@@ -137,7 +136,7 @@ public class CheckinClient {
.loggingId(new Random().nextLong()) // TODO: static
.meid(deviceIdent.meid)
.otaCert(Collections.singletonList("71Q6Rn2DDZl1zPDVaaeEHItd"))
- .serial(Build.SERIAL)
+ .serial(Build.SERIAL != null && !Build.SERIAL.isEmpty() ? Build.SERIAL : null)
.timeZone(TimeZone.getDefault().getID())
.userName((String) TODO)
.userSerialNumber((Integer) TODO)
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 355800d1..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);
@@ -71,7 +71,8 @@ public class CheckinManager {
ContentResolver resolver = context.getContentResolver();
for (CheckinResponse.GservicesSetting setting : response.setting) {
- GServices.setString(resolver, setting.name.utf8(), setting.value_.utf8());
+ if (setting.name != null && setting.value_ != null)
+ GServices.setString(resolver, setting.name.utf8(), setting.value_.utf8());
}
return info;
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..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()));
@@ -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);
}
}
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 4b6551bd..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
@@ -18,7 +18,6 @@ package org.microg.gms.checkin;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.os.Build.VERSION.SDK_INT;
import static org.microg.gms.checkin.CheckinService.EXTRA_FORCE_CHECKIN;
import static org.microg.gms.checkin.CheckinService.REGULAR_CHECKIN_INTERVAL;
@@ -42,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;
@@ -54,7 +53,7 @@ public class TriggerReceiver extends WakefulBroadcastReceiver {
Intent subIntent = new Intent(context, CheckinService.class);
subIntent.putExtra(EXTRA_FORCE_CHECKIN, force);
startWakefulService(new ForegroundServiceContext(context), subIntent);
- } else if (SDK_INT >= 23) {
+ } else {
// no network, register a network callback to retry when we have internet
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_INTERNET)
diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/GcmDatabase.java b/play-services-core/src/main/java/org/microg/gms/gcm/GcmDatabase.java
index d9881dd8..d19ce6ea 100644
--- a/play-services-core/src/main/java/org/microg/gms/gcm/GcmDatabase.java
+++ b/play-services-core/src/main/java/org/microg/gms/gcm/GcmDatabase.java
@@ -10,7 +10,6 @@ import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
-import android.os.Build;
import android.text.TextUtils;
import java.util.ArrayList;
@@ -55,9 +54,7 @@ public class GcmDatabase extends SQLiteOpenHelper {
public GcmDatabase(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.context = context;
- if (Build.VERSION.SDK_INT >= 16) {
- this.setWriteAheadLoggingEnabled(true);
- }
+ this.setWriteAheadLoggingEnabled(true);
}
public static class App {
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 6a6889ff..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
@@ -19,8 +19,42 @@ package org.microg.gms.gcm;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.os.Build.VERSION.SDK_INT;
import static org.microg.gms.common.PackageUtils.warnIfNotPersistentProcess;
-import static org.microg.gms.gcm.GcmConstants.*;
-import static org.microg.gms.gcm.McsConstants.*;
+import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_RECEIVE;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_APP;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_APP_OVERRIDE;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_COLLAPSE_KEY;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_FROM;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_MESSAGE_ID;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_MESSENGER;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_RAWDATA;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_RAWDATA_BASE64;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_REGISTRATION_ID;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_SEND_FROM;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_SEND_TO;
+import static org.microg.gms.gcm.GcmConstants.EXTRA_TTL;
+import static org.microg.gms.gcm.McsConstants.ACTION_ACK;
+import static org.microg.gms.gcm.McsConstants.ACTION_CONNECT;
+import static org.microg.gms.gcm.McsConstants.ACTION_HEARTBEAT;
+import static org.microg.gms.gcm.McsConstants.ACTION_RECONNECT;
+import static org.microg.gms.gcm.McsConstants.ACTION_SEND;
+import static org.microg.gms.gcm.McsConstants.EXTRA_REASON;
+import static org.microg.gms.gcm.McsConstants.MCS_CLOSE_TAG;
+import static org.microg.gms.gcm.McsConstants.MCS_DATA_MESSAGE_STANZA_TAG;
+import static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_ACK_TAG;
+import static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_PING_TAG;
+import static org.microg.gms.gcm.McsConstants.MCS_IQ_STANZA_TAG;
+import static org.microg.gms.gcm.McsConstants.MCS_LOGIN_REQUEST_TAG;
+import static org.microg.gms.gcm.McsConstants.MCS_LOGIN_RESPONSE_TAG;
+import static org.microg.gms.gcm.McsConstants.MSG_ACK;
+import static org.microg.gms.gcm.McsConstants.MSG_CONNECT;
+import static org.microg.gms.gcm.McsConstants.MSG_HEARTBEAT;
+import static org.microg.gms.gcm.McsConstants.MSG_INPUT;
+import static org.microg.gms.gcm.McsConstants.MSG_INPUT_ERROR;
+import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT;
+import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_DONE;
+import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_ERROR;
+import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_READY;
+import static org.microg.gms.gcm.McsConstants.MSG_TEARDOWN;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
@@ -34,15 +68,16 @@ import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.Messenger;
import android.os.Parcelable;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.util.Base64;
import android.util.Log;
import androidx.annotation.Nullable;
@@ -66,7 +101,6 @@ import org.microg.gms.gcm.mcs.IqStanza;
import org.microg.gms.gcm.mcs.LoginRequest;
import org.microg.gms.gcm.mcs.LoginResponse;
import org.microg.gms.gcm.mcs.Setting;
-import org.microg.mgms.settings.SettingsProvider;
import java.io.Closeable;
import java.lang.reflect.Field;
@@ -76,6 +110,7 @@ import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import javax.net.ssl.SSLContext;
@@ -136,10 +171,10 @@ public class McsService extends Service implements Handler.Callback {
@Nullable
private Method addPowerSaveTempWhitelistAppMethod;
@Nullable
- @RequiresApi(Build.VERSION_CODES.S)
+ @RequiresApi(31)
private Object powerExemptionManager;
@Nullable
- @RequiresApi(Build.VERSION_CODES.S)
+ @RequiresApi(31)
private Method addToTemporaryAllowListMethod;
private class HandlerThread extends Thread {
@@ -154,7 +189,7 @@ public class McsService extends Service implements Handler.Callback {
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "mcs");
wakeLock.setReferenceCounted(false);
synchronized (McsService.class) {
- rootHandler = new Handler(Looper.myLooper(), McsService.this);
+ rootHandler = new Handler(Objects.requireNonNull(Looper.myLooper()), McsService.this);
if (connectIntent != null) {
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_CONNECT, connectIntent));
WakefulBroadcastReceiver.completeWakefulIntent(connectIntent);
@@ -174,12 +209,12 @@ 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) {
try {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ if (SDK_INT >= 31) {
Class> powerExemptionManagerClass = Class.forName("android.os.PowerExemptionManager");
powerExemptionManager = getSystemService(powerExemptionManagerClass);
addToTemporaryAllowListMethod =
@@ -265,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);
}
@@ -277,14 +312,13 @@ public class McsService extends Service implements Handler.Callback {
closeAll();
}
logd(context, "Scheduling heartbeat in " + heartbeatMs / 1000 + " seconds...");
- // This is supposed to work even when running in idle and without battery optimization disabled
alarmManager.setExactAndAllowWhileIdle(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + heartbeatMs, heartbeatIntent);
}
public synchronized static long getCurrentDelay() {
long delay = currentDelay == 0 ? 5000 : currentDelay;
- if (currentDelay < SettingsProvider.INTERVAL) currentDelay += 10000;
- if (currentDelay >= SettingsProvider.INTERVAL && currentDelay < 600000) currentDelay += SettingsProvider.INTERVAL;
+ if (currentDelay < 60000) currentDelay += 10000;
+ if (currentDelay >= 60000 && currentDelay < 600000) currentDelay += 60000;
return delay;
}
@@ -324,6 +358,7 @@ public class McsService extends Service implements Handler.Callback {
String messageId = intent.getStringExtra(EXTRA_MESSAGE_ID);
String collapseKey = intent.getStringExtra(EXTRA_COLLAPSE_KEY);
+ Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);
intent.removeExtra(EXTRA_MESSENGER);
Parcelable app = intent.getParcelableExtra(EXTRA_APP);
@@ -341,8 +376,16 @@ public class McsService extends Service implements Handler.Callback {
}
intent.removeExtra(EXTRA_APP);
+ int ttl;
try {
- intent.hasExtra(EXTRA_TTL);
+ if (intent.hasExtra(EXTRA_TTL)) {
+ ttl = Integer.parseInt(intent.getStringExtra(EXTRA_TTL));
+ if (ttl < 0 || ttl > maxTtl) {
+ ttl = maxTtl;
+ }
+ } else {
+ ttl = maxTtl;
+ }
} catch (NumberFormatException e) {
// TODO: error TtlUnsupported
Log.w(TAG, e);
@@ -535,15 +578,17 @@ public class McsService extends Service implements Handler.Callback {
intent.setAction(ACTION_C2DM_RECEIVE);
intent.putExtra(EXTRA_FROM, msg.from);
intent.putExtra(EXTRA_MESSAGE_ID, msg.id);
- if (msg.persistent_id != null) {
- intent.putExtra(EXTRA_MESSAGE_ID, msg.persistent_id);
+ if (msg.persistent_id != null) intent.putExtra(EXTRA_MESSAGE_ID, msg.persistent_id);
+ if (msg.token != null) intent.putExtra(EXTRA_COLLAPSE_KEY, msg.token);
+ if (msg.raw_data != null) {
+ intent.putExtra(EXTRA_RAWDATA_BASE64, Base64.encodeToString(msg.raw_data.toByteArray(), Base64.DEFAULT));
+ intent.putExtra(EXTRA_RAWDATA, msg.raw_data.toByteArray());
}
if (app.wakeForDelivery) {
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
} else {
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
}
- if (msg.token != null) intent.putExtra(EXTRA_COLLAPSE_KEY, msg.token);
for (AppData appData : msg.app_data) {
intent.putExtra(appData.key, appData.value_);
}
@@ -567,7 +612,7 @@ public class McsService extends Service implements Handler.Callback {
sendOrderedBroadcast(intent, null);
} else {
List infos = getPackageManager().queryBroadcastReceivers(intent, PackageManager.GET_RESOLVED_FILTER);
- if (infos == null || infos.isEmpty()) {
+ if (infos.isEmpty()) {
logd(this, "No target for message, wut?");
} else {
for (ResolveInfo resolveInfo : infos) {
@@ -589,7 +634,7 @@ public class McsService extends Service implements Handler.Callback {
}
private void addPowerSaveTempWhitelistApp(String packageName) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ if (SDK_INT >= 31) {
try {
if (addToTemporaryAllowListMethod != null && powerExemptionManager != null) {
logd(this, "Adding app " + packageName + " to the temp allowlist");
@@ -633,12 +678,12 @@ public class McsService extends Service implements Handler.Callback {
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_OUTPUT, type, 0, message));
}
- private void sendOutputStream(int what, int arg, Object obj) {
+ private void sendOutputStream(int arg, Object obj) {
McsOutputStream os = outputStream;
if (os != null && os.isAlive()) {
Handler outputHandler = os.getHandler();
if (outputHandler != null)
- outputHandler.sendMessage(outputHandler.obtainMessage(what, arg, 0, obj));
+ outputHandler.sendMessage(outputHandler.obtainMessage(McsConstants.MSG_OUTPUT, arg, 0, obj));
}
}
@@ -649,7 +694,7 @@ public class McsService extends Service implements Handler.Callback {
handleInput(msg.arg1, (Message) msg.obj);
return true;
case MSG_OUTPUT:
- sendOutputStream(MSG_OUTPUT, msg.arg1, msg.obj);
+ sendOutputStream(msg.arg1, msg.obj);
return true;
case MSG_INPUT_ERROR:
case MSG_OUTPUT_ERROR:
diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java b/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java
index 1dcfec44..bc93194e 100644
--- a/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java
+++ b/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java
@@ -147,7 +147,7 @@ public class PushRegisterManager {
resultBundle.putString(EXTRA_REGISTRATION_ID, attachRequestId(response.token, requestId));
}
} else {
- if (!request.app.equals(response.deleted) && !request.app.equals(response.token)) {
+ if (!request.app.equals(response.deleted) && !request.app.equals(response.token) && !request.sender.equals(response.token)) {
database.noteAppRegistrationError(request.app, response.responseText);
resultBundle.putString(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));
} else {
diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java b/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java
index dbc21088..80c7fd83 100644
--- a/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java
+++ b/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java
@@ -123,7 +123,7 @@ public class RegisterRequest extends HttpFormClient.Request {
public RegisterRequest extraParams(Bundle extraBundle) {
for (String key : extraBundle.keySet()) {
- if (!key.equals(GcmConstants.EXTRA_SENDER) && !key.equals(GcmConstants.EXTRA_DELETE)) {
+ if (!key.equals(GcmConstants.EXTRA_SENDER) && !key.equals(GcmConstants.EXTRA_DELETE) && !key.equals(GcmConstants.EXTRA_APP)) {
extraParam(key, extraBundle.getString(key));
}
}
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 245d5c2a..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
@@ -17,7 +17,6 @@
package org.microg.gms.gcm;
import static android.os.Build.VERSION.SDK_INT;
-import static android.os.Build.VERSION_CODES.N;
import static org.microg.gms.gcm.McsConstants.ACTION_CONNECT;
import static org.microg.gms.gcm.McsConstants.ACTION_HEARTBEAT;
import static org.microg.gms.gcm.McsConstants.EXTRA_REASON;
@@ -31,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;
@@ -44,7 +43,7 @@ public class TriggerReceiver extends WakefulBroadcastReceiver {
* "Project Svelte" is just there to f**k things up...
*/
public synchronized static void register(Context context) {
- if (SDK_INT >= N && !registered) {
+ if (SDK_INT >= 24 && !registered) {
IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
context.getApplicationContext().registerReceiver(new TriggerReceiver(), intentFilter);
registered = true;
@@ -68,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/java/org/microg/gms/gservices/GServices.java b/play-services-core/src/main/java/org/microg/gms/gservices/GServices.java
index 79543f47..5c811f28 100644
--- a/play-services-core/src/main/java/org/microg/gms/gservices/GServices.java
+++ b/play-services-core/src/main/java/org/microg/gms/gservices/GServices.java
@@ -21,10 +21,12 @@ import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
+import org.microg.gms.base.core.BuildConfig;
+
public class GServices {
- public static final Uri CONTENT_URI = Uri.parse("content://com.mgoogle.android.gsf.gservices");
- public static final Uri MAIN_URI = Uri.parse("content://com.mgoogle.android.gsf.gservices/main");
- public static final Uri OVERRIDE_URI = Uri.parse("content://com.mgoogle.android.gsf.gservices/override");
+ public static final Uri CONTENT_URI = Uri.parse("content://" + BuildConfig.BASE_PACKAGE_NAME + ".android.gsf.gservices");
+ public static final Uri MAIN_URI = Uri.parse("content://" + BuildConfig.BASE_PACKAGE_NAME + ".android.gsf.gservices/main");
+ public static final Uri OVERRIDE_URI = Uri.parse("content://" + BuildConfig.BASE_PACKAGE_NAME + ".android.gsf.gservices/override");
public static int setString(ContentResolver resolver, String key, String value) {
ContentValues values = new ContentValues();
diff --git a/play-services-core/src/main/java/org/microg/gms/gservices/GServicesProvider.java b/play-services-core/src/main/java/org/microg/gms/gservices/GServicesProvider.java
index 2a95655b..3d3a8189 100644
--- a/play-services-core/src/main/java/org/microg/gms/gservices/GServicesProvider.java
+++ b/play-services-core/src/main/java/org/microg/gms/gservices/GServicesProvider.java
@@ -29,6 +29,8 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+import org.microg.gms.base.core.BuildConfig;
+
/**
* Originally found in Google Services Framework (com.google.android.gsf), this provides a generic
* key-value store, that is written by the checkin service and read from various Google Apps.
@@ -37,7 +39,7 @@ import java.util.Set;
* if certain "experiments" are enabled on the device.
*/
public class GServicesProvider extends ContentProvider {
- public static final Uri CONTENT_URI = Uri.parse("content://com.mgoogle.android.gsf.gservices/");
+ public static final Uri CONTENT_URI = Uri.parse("content://" + BuildConfig.BASE_PACKAGE_NAME + ".android.gsf.gservices/");
public static final Uri MAIN_URI = Uri.withAppendedPath(CONTENT_URI, "main");
public static final Uri OVERRIDE_URI = Uri.withAppendedPath(CONTENT_URI, "override");
public static final Uri PREFIX_URI = Uri.withAppendedPath(CONTENT_URI, "prefix");
diff --git a/play-services-core/src/main/java/org/microg/mgms/settings/GoogleSettingsProvider.java b/play-services-core/src/main/java/org/microg/gms/settings/GoogleSettingsProvider.java
similarity index 97%
rename from play-services-core/src/main/java/org/microg/mgms/settings/GoogleSettingsProvider.java
rename to play-services-core/src/main/java/org/microg/gms/settings/GoogleSettingsProvider.java
index 3ab7f51c..da3e5094 100644
--- a/play-services-core/src/main/java/org/microg/mgms/settings/GoogleSettingsProvider.java
+++ b/play-services-core/src/main/java/org/microg/gms/settings/GoogleSettingsProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.microg.mgms.settings;
+package org.microg.gms.settings;
import android.content.ContentProvider;
import android.content.ContentValues;
diff --git a/play-services-core/src/main/java/org/microg/gms/ui/AccountSettingsActivity.java b/play-services-core/src/main/java/org/microg/gms/ui/LegacyAccountSettingsActivity.java
old mode 100755
new mode 100644
similarity index 91%
rename from play-services-core/src/main/java/org/microg/gms/ui/AccountSettingsActivity.java
rename to play-services-core/src/main/java/org/microg/gms/ui/LegacyAccountSettingsActivity.java
index fa099d49..fc015f5e
--- a/play-services-core/src/main/java/org/microg/gms/ui/AccountSettingsActivity.java
+++ b/play-services-core/src/main/java/org/microg/gms/ui/LegacyAccountSettingsActivity.java
@@ -18,7 +18,6 @@ package org.microg.gms.ui;
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.os.Build;
import android.os.Bundle;
import androidx.annotation.Nullable;
@@ -34,9 +33,10 @@ import org.microg.tools.ui.ResourceSettingsFragment;
import static android.accounts.AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE;
import static android.accounts.AccountManager.VISIBILITY_NOT_VISIBLE;
import static android.accounts.AccountManager.VISIBILITY_VISIBLE;
+import static android.os.Build.VERSION.SDK_INT;
import static org.microg.gms.auth.AuthManager.PREF_AUTH_VISIBLE;
-public class AccountSettingsActivity extends AbstractSettingsActivity {
+public class LegacyAccountSettingsActivity extends AbstractSettingsActivity {
@Override
protected Fragment getFragment() {
@@ -45,7 +45,7 @@ public class AccountSettingsActivity extends AbstractSettingsActivity {
public static class AccountSettingsFragment extends ResourceSettingsFragment {
public AccountSettingsFragment() {
- preferencesResource = R.xml.preferences_account;
+ preferencesResource = R.xml.preferences_google_more;
}
@Override
@@ -53,7 +53,7 @@ public class AccountSettingsActivity extends AbstractSettingsActivity {
super.onCreatePreferences(savedInstanceState, rootKey);
Preference pref = findPreference(PREF_AUTH_VISIBLE);
if (pref != null) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+ if (SDK_INT < 26) {
pref.setVisible(false);
} else {
pref.setOnPreferenceChangeListener((preference, newValue) -> {
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 c60833ec..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,6 +1,6 @@
package org.microg.gms.ui;
-import android.os.Build;
+import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.Nullable;
@@ -10,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() {
@@ -23,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 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- 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);
}
@@ -35,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/java/org/microg/tools/AccountPickerActivity.java b/play-services-core/src/main/java/org/microg/tools/AccountPickerActivity.java
index 4c596f32..69d87394 100755
--- a/play-services-core/src/main/java/org/microg/tools/AccountPickerActivity.java
+++ b/play-services-core/src/main/java/org/microg/tools/AccountPickerActivity.java
@@ -16,16 +16,15 @@
package org.microg.tools;
-import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
+import androidx.appcompat.app.AppCompatActivity;
/**
* This is just an activity that forwards to the systems native account picker
*/
-public class AccountPickerActivity extends Activity {
- private static final int REQUEST_CODE = AccountPickerActivity.class.hashCode();
+public class AccountPickerActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -36,16 +35,8 @@ public class AccountPickerActivity extends Activity {
ComponentName.unflattenFromString("android/.accounts.ChooseTypeAndAccountActivity");
intent.setClassName(componentName.getPackageName(), componentName.getClassName());
intent.putExtras(extras);
- startActivityForResult(intent, REQUEST_CODE);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUEST_CODE) {
- setResult(resultCode, data);
- finish();
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- }
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
+ finish();
}
}
diff --git a/play-services-core/src/main/kotlin/com/google/android/gms/common/GoogleCertificatesImpl.kt b/play-services-core/src/main/kotlin/com/google/android/gms/common/GoogleCertificatesImpl.kt
new file mode 100644
index 00000000..e1fb7a21
--- /dev/null
+++ b/play-services-core/src/main/kotlin/com/google/android/gms/common/GoogleCertificatesImpl.kt
@@ -0,0 +1,90 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package com.google.android.gms.common
+
+import android.content.pm.PackageManager
+import android.os.IBinder
+import android.os.Parcel
+import android.util.Log
+import androidx.annotation.Keep
+import com.google.android.gms.common.internal.CertData
+import com.google.android.gms.common.internal.IGoogleCertificatesApi
+import com.google.android.gms.dynamic.IObjectWrapper
+import com.google.android.gms.dynamic.ObjectWrapper
+import org.microg.gms.common.PackageUtils
+import org.microg.gms.utils.warnOnTransactionIssues
+
+private const val TAG = "GoogleCertificates"
+
+@Keep
+class GoogleCertificatesImpl : IGoogleCertificatesApi.Stub() {
+ private val googleCertificates = emptySet()
+ private val googleReleaseCertificates = emptySet()
+
+ override fun getGoogleCertificates(): IObjectWrapper {
+ Log.d(TAG, "unimplemented Method: getGoogleCertificates")
+ return ObjectWrapper.wrap(googleCertificates.toTypedArray())
+ }
+
+ override fun getGoogleReleaseCertificates(): IObjectWrapper {
+ Log.d(TAG, "unimplemented Method: getGoogleReleaseCertificates")
+ return ObjectWrapper.wrap(googleReleaseCertificates.toTypedArray())
+ }
+
+ override fun isGoogleReleaseSigned(packageName: String, certData: IObjectWrapper): Boolean {
+ return PackageUtils.isGooglePackage(packageName, ObjectWrapper.unwrapTyped(certData, ByteArray::class.java))
+ }
+
+ override fun isGoogleSigned(packageName: String, certData: IObjectWrapper): Boolean {
+ return PackageUtils.isGooglePackage(packageName, ObjectWrapper.unwrapTyped(certData, ByteArray::class.java))
+ }
+
+ override fun isGoogleOrPlatformSigned(query: GoogleCertificatesQuery, packageManager: IObjectWrapper): Boolean {
+ val pm = ObjectWrapper.unwrapTyped(packageManager, PackageManager::class.java)
+ return if (query == null || query.callingPackage == null) {
+ false
+ } else if (query.getCertData() == null) {
+ if (pm == null) false else PackageUtils.isGooglePackage(pm, query.callingPackage)
+ } else {
+ PackageUtils.isGooglePackage(query.callingPackage, query.getCertData().bytes)
+ }
+ }
+
+ override fun isPackageGoogleOrPlatformSigned(query: GoogleCertificatesLookupQuery): GoogleCertificatesLookupResponse {
+ return certificateLookup(query, true)
+ }
+
+ override fun isPackageGoogleOrPlatformSignedAvailable(): Boolean {
+ return true
+ }
+
+ override fun queryPackageSigned(query: GoogleCertificatesLookupQuery): GoogleCertificatesLookupResponse {
+ if (!isFineGrainedPackageVerificationAvailable) throw IllegalStateException("API unavailable")
+ return certificateLookup(query, false)
+ }
+
+ override fun isFineGrainedPackageVerificationAvailable(): Boolean {
+ return true
+ }
+
+ private fun certificateLookup(query: GoogleCertificatesLookupQuery, allowPlatform: Boolean): GoogleCertificatesLookupResponse {
+ val context = query.context
+ ?: return GoogleCertificatesLookupResponse(false, "context is null", 5, 1)
+ val packageManager = context.packageManager
+ ?: return GoogleCertificatesLookupResponse(false, "context has no package manager", 5, 1)
+ val callingPackage = query.callingPackage
+ ?: return GoogleCertificatesLookupResponse(false, "callingPackage is null", 5, 1)
+ val signatureDigest = PackageUtils.firstSignatureDigest(packageManager, callingPackage)
+ ?: return GoogleCertificatesLookupResponse(false, "callingPackage not found", 4, 1)
+ return if (PackageUtils.isGooglePackage(callingPackage, signatureDigest)) {
+ GoogleCertificatesLookupResponse(true, null, 1, 3)
+ } else {
+ GoogleCertificatesLookupResponse(false, "not allowed", 2, 1)
+ }
+ }
+
+ override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
+ warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }
+}
diff --git a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/LoaderActivity.kt b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/LoaderActivity.kt
new file mode 100644
index 00000000..c1a4a2da
--- /dev/null
+++ b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/LoaderActivity.kt
@@ -0,0 +1,165 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.accountsettings.ui
+
+import android.accounts.AccountManager
+import android.content.Intent
+import android.content.Intent.ACTION_VIEW
+import android.content.Intent.CATEGORY_BROWSABLE
+import android.content.Intent.FLAG_ACTIVITY_FORWARD_RESULT
+import android.net.Uri
+import android.os.Bundle
+import android.util.Log
+import androidx.appcompat.app.AppCompatActivity
+import org.microg.gms.auth.AuthConstants.DEFAULT_ACCOUNT_TYPE
+import org.microg.gms.common.PackageUtils
+import org.microg.tools.AccountPickerActivity
+
+private const val TAG = "AccountSettingsLoader"
+
+private val ALLOWED_FALLBACK_PREFIXES = setOf("https://myaccount.google.com/", "https://takeout.google.com/")
+private val BROWSABLE_SCREEN_IDS = setOf(1, 200, 400, 502, 527, 10003, 10050, 12700, 12701)
+private val ACCOUNT_CHOOSER_URI = Uri.parse("https://accounts.google.com/AccountChooser")
+
+private const val QUERY_PARAM_CONTINUE = "continue"
+private const val QUERY_PARAM_LANG = "hl"
+private const val QUERY_PARAM_EMAIL = "Email"
+
+private const val EXTRA_ALLOWABLE_ACCOUNT_TYPES = "allowableAccountTypes"
+
+private const val REQUEST_ACCOUNT_PICKER = 1
+
+@Suppress("DEPRECATION")
+class LoaderActivity : AppCompatActivity() {
+ private var canAskForAccount = false
+
+ private fun launchFallback() {
+ val fallbackUrl = intent?.getStringExtra(EXTRA_FALLBACK_URL)
+
+ if (fallbackUrl == null) {
+ Log.d(TAG, "No fallback")
+ finishResult(RESULT_CANCELED)
+ } else if (fallbackUrl in ALLOWED_FALLBACK_PREFIXES) {
+ // TODO: Error screen?
+ Log.d(TAG, "Illegal fallback url")
+ finishResult(RESULT_CANCELED)
+ } else {
+ val fallbackAuth = intent?.getBooleanExtra(EXTRA_FALLBACK_AUTH, false) ?: false
+ val uri = if (fallbackAuth) {
+ val builder = ACCOUNT_CHOOSER_URI.buildUpon().appendQueryParameter(QUERY_PARAM_CONTINUE, fallbackUrl)
+ val accountName = intent?.getStringExtra(EXTRA_ACCOUNT_NAME)
+ if (!accountName.isNullOrBlank()) {
+ builder.appendQueryParameter(QUERY_PARAM_EMAIL, accountName)
+ }
+ val lang = Uri.parse(fallbackUrl).getQueryParameter(QUERY_PARAM_LANG)
+ if (lang != null) {
+ builder.appendQueryParameter(QUERY_PARAM_LANG, lang)
+ }
+ builder.build()
+ } else {
+ Uri.parse(fallbackUrl)
+ }
+ Log.d(TAG, "Opening fallback $fallbackUrl")
+ val intent = Intent(ACTION_VIEW, uri).apply { addCategory(CATEGORY_BROWSABLE) }
+ startActivity(intent)
+ finishResult(RESULT_OK)
+ }
+ }
+
+ private fun launchMain() {
+ val requestedAccountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME)
+ val ignoreAccount = intent?.getBooleanExtra(EXTRA_IGNORE_ACCOUNT, false) ?: false
+ val accounts = AccountManager.get(this).getAccountsByType(DEFAULT_ACCOUNT_TYPE)
+ val account = if (requestedAccountName != null) {
+ val account = accounts.find { it.name == requestedAccountName }
+ if (account == null) {
+ // TODO: Error screen?
+ Log.d(TAG, "Account not found: $requestedAccountName")
+ return finishResult(RESULT_CANCELED)
+ }
+ account
+ } else if (accounts.isEmpty()) {
+ if (intent?.getStringExtra(EXTRA_FALLBACK_URL) != null) {
+ return launchFallback()
+ } else {
+ // TODO: Error screen?
+ Log.d(TAG, "No account configured")
+ return finishResult(RESULT_CANCELED)
+ }
+ } else if (accounts.size > 1) {
+ if (canAskForAccount) {
+ val intent = Intent(this, AccountPickerActivity::class.java)
+ intent.putExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES, arrayOf(DEFAULT_ACCOUNT_TYPE))
+ startActivityForResult(intent, REQUEST_ACCOUNT_PICKER)
+ canAskForAccount = false
+ return
+ } else {
+ return finishResult(RESULT_CANCELED)
+ }
+ } else {
+ accounts.first()
+ }
+
+ val intent = Intent(this, MainActivity::class.java).apply {
+ action = intent.action
+ if (intent.hasExtra(EXTRA_THEME_CHOICE)) putExtra(EXTRA_THEME_CHOICE, intent.getIntExtra(EXTRA_THEME_CHOICE, 0))
+ putExtra(EXTRA_ACCOUNT_NAME, account.name)
+ if (ignoreAccount) putExtra(EXTRA_IGNORE_ACCOUNT, true)
+ putExtra(EXTRA_SCREEN_ID, intent.getIntExtra(EXTRA_SCREEN_ID, 1))
+ for (it in intent.extras?.keySet().orEmpty()) {
+ if (it.startsWith(EXTRA_SCREEN_OPTIONS_PREFIX)) putExtra(it, intent.getStringExtra(it))
+ }
+ putExtra(EXTRA_CALLING_PACKAGE_NAME, callingActivity?.packageName)
+ if (intent.action != ACTION_BROWSE_SETTINGS) {
+ addFlags(FLAG_ACTIVITY_FORWARD_RESULT)
+ }
+ }
+
+ startActivity(intent)
+
+ if (!isFinishing && !isChangingConfigurations) {
+ finishResult(RESULT_OK)
+ }
+ }
+
+ @Deprecated("Deprecated in Java")
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (requestCode == REQUEST_ACCOUNT_PICKER) {
+ if (resultCode == RESULT_OK && data?.hasExtra(AccountManager.KEY_ACCOUNT_NAME) == true) {
+ intent.putExtra(EXTRA_ACCOUNT_NAME, data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME))
+ launchMain()
+ } else {
+ finishResult(resultCode)
+ }
+ } else {
+ super.onActivityResult(requestCode, resultCode, data)
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ canAskForAccount = true
+ val extras = intent?.extras?.also { it.keySet() }
+ Log.d(TAG, "Invoked with ${intent.action} and extras $extras")
+
+ super.onCreate(savedInstanceState)
+
+ val isMainAllowed = if (intent == null || intent.action != ACTION_BROWSE_SETTINGS)
+ PackageUtils.isGooglePackage(this, callingActivity?.packageName)
+ else
+ extras?.getInt(EXTRA_SCREEN_ID, -1) in BROWSABLE_SCREEN_IDS
+
+ if (!isMainAllowed) {
+ launchFallback()
+ } else if (!isFinishing && !isChangingConfigurations){
+ launchMain()
+ }
+ }
+
+ private fun finishResult(resultCode: Int) {
+ setResult(resultCode)
+ finish()
+ }
+}
\ No newline at end of file
diff --git a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt
new file mode 100644
index 00000000..441a2e3b
--- /dev/null
+++ b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/MainActivity.kt
@@ -0,0 +1,185 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.accountsettings.ui
+
+import android.accounts.Account
+import android.accounts.AccountManager
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import android.webkit.WebView
+import android.widget.ProgressBar
+import android.widget.RelativeLayout
+import android.widget.RelativeLayout.LayoutParams.MATCH_PARENT
+import android.widget.RelativeLayout.LayoutParams.WRAP_CONTENT
+import androidx.appcompat.app.AppCompatActivity
+import org.microg.gms.auth.AuthConstants
+import org.microg.gms.common.Constants
+
+private const val TAG = "AccountSettings"
+
+// TODO: There likely is some API to figure those out...
+private val SCREEN_ID_TO_URL = hashMapOf(
+ 1 to "https://myaccount.google.com",
+ 200 to "https://myaccount.google.com/privacycheckup",
+ 203 to "https://myaccount.google.com/email",
+ 204 to "https://myaccount.google.com/phone",
+ 205 to "https://myaccount.google.com/birthday",
+ 206 to "https://myaccount.google.com/gender",
+ 210 to "https://myaccount.google.com/locationsharing",
+ 214 to "https://myaccount.google.com/dashboard",
+ 215 to "https://takeout.google.com",
+ 216 to "https://myaccount.google.com/inactive",
+ 219 to "https://myactivity.google.com/myactivity",
+ 220 to "https://www.google.com/maps/timeline",
+ 224 to "https://myactivity.google.com/activitycontrols?settings=search",
+ 227 to "https://myactivity.google.com/activitycontrols?settings=location",
+ 231 to "https://myactivity.google.com/activitycontrols?settings=youtube",
+ 235 to "https://myactivity.google.com/activitycontrols/youtube",
+ 238 to "https://www.google.com/setting/search/privateresults/",
+ 241 to "https://myaccount.google.com/communication-preferences",
+ 300 to "https://myaccount.google.com/language",
+ 301 to "https://drive.google.com/settings/storage",
+ 302 to "https://myaccount.google.com/deleteservices",
+ 303 to "https://myaccount.google.com/deleteaccount",
+ 307 to "https://payments.google.com/payments/home",
+ 308 to "https://myaccount.google.com/subscriptions",
+ 309 to "https://myaccount.google.com/purchases",
+ 310 to "https://myaccount.google.com/reservations",
+ 312 to "https://myaccount.google.com/accessibility",
+ 313 to "https://myaccount.google.com/inputtools",
+ 400 to "https://myaccount.google.com/security-checkup/",
+ 401 to "https://myaccount.google.com/signinoptions/password",
+ 403 to "https://myaccount.google.com/signinoptions/two-step-verification",
+ 406 to "https://myaccount.google.com/signinoptions/rescuephone",
+ 407 to "https://myaccount.google.com/recovery/email",
+ 409 to "https://myaccount.google.com/notifications",
+ 410 to "https://myaccount.google.com/device-activity",
+ 417 to "https://myaccount.google.com/find-your-phone",
+ 425 to "https://myaccount.google.com/account-enhanced-safe-browsing",
+ 426 to "https://myaccount.google.com/two-step-verification/authenticator",
+ 427 to "https://myaccount.google.com/two-step-verification/backup-codes",
+ 429 to "https://myaccount.google.com/two-step-verification/security-keys",
+ 430 to "https://myaccount.google.com/two-step-verification/prompt",
+ 431 to "https://myaccount.google.com/connections",
+ 432 to "https://myaccount.google.com/two-step-verification/phone-numbers",
+ 433 to "https://myaccount.google.com/signinoptions/passkeys",
+ 437 to "https://myaccount.google.com/signinoptions/passwordoptional",
+ 500 to "https://policies.google.com/privacy",
+ 503 to "https://policies.google.com/terms",
+ 519 to "https://myaccount.google.com/yourdata/maps",
+ 520 to "https://myaccount.google.com/yourdata/search",
+ 530 to "https://fit.google.com/privacy/settings",
+ 547 to "https://myactivity.google.com/product/search",
+ 562 to "https://myaccount.google.com/yourdata/youtube",
+ 10003 to "https://myaccount.google.com/personal-info",
+ 10004 to "https://myaccount.google.com/data-and-privacy",
+ 10005 to "https://myaccount.google.com/people-and-sharing",
+ 10006 to "https://myaccount.google.com/security",
+ 10007 to "https://myaccount.google.com/payments-and-subscriptions",
+ 10015 to "https://support.google.com/accounts",
+ 10050 to "https://myaccount.google.com/profile",
+ 10090 to "https://myaccount.google.com/profile/name",
+ 10704 to "https://www.google.com/account/about",
+ 10706 to "https://myaccount.google.com/profile/profiles-summary",
+ 10728 to "https://myaccount.google.com/data-and-privacy/how-data-improves-experience",
+ 10729 to "https://myaccount.google.com/data-and-privacy/data-visibility",
+ 10759 to "https://myaccount.google.com/address/home",
+ 10760 to "https://myaccount.google.com/address/work",
+)
+
+private val ALLOWED_WEB_PREFIXES = setOf(
+ "https://accounts.google.com/",
+ "https://myaccount.google.com/",
+ "https://one.google.com/",
+ "https://myactivity.google.com/",
+ "https://timeline.google.com/",
+ "https://takeout.google.com/",
+ "https://www.google.com/maps/timeline",
+ "https://www.google.com/setting/",
+ "https://drive.google.com/settings/",
+ "https://drive.google.com/accounts/",
+ "https://drive.google.com/u/1/settings/",
+ "https://payments.google.com/",
+ "https://policies.google.com/",
+ "https://fit.google.com/privacy/settings",
+ "https://maps.google.com/maps/timeline"
+)
+
+private val ACTION_TO_SCREEN_ID = hashMapOf(
+ ACTION_MY_ACCOUNT to 1,
+ ACTION_ACCOUNT_PREFERENCES_SETTINGS to 1,
+ ACTION_SECURITY_SETTINGS to 10006,
+ ACTION_PRIVACY_SETTINGS to 10004,
+)
+
+@Suppress("DEPRECATION")
+class MainActivity : AppCompatActivity() {
+ private lateinit var webView: WebView
+
+ private fun getSelectedAccountName(): String? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ val extras = intent?.extras?.also { it.keySet() }
+ Log.d(TAG, "Invoked with ${intent.action} and extras $extras")
+ super.onCreate(savedInstanceState)
+
+ val screenId = intent?.getIntExtra(EXTRA_SCREEN_ID, -1).takeIf { it != -1 } ?: ACTION_TO_SCREEN_ID[intent.action] ?: 1
+ val screenOptions = intent.extras?.keySet().orEmpty()
+ .filter { it.startsWith(EXTRA_SCREEN_OPTIONS_PREFIX) }
+ .map { it.substring(EXTRA_SCREEN_OPTIONS_PREFIX.length) to intent.getStringExtra(it) }
+ .toMap()
+
+ val callingPackage = intent?.getStringExtra(EXTRA_CALLING_PACKAGE_NAME) ?: callingActivity?.packageName ?: Constants.GMS_PACKAGE_NAME
+
+ val ignoreAccount = intent?.getBooleanExtra(EXTRA_IGNORE_ACCOUNT, false) ?: false
+ val accountName = if (ignoreAccount) null else {
+ val accounts = AccountManager.get(this).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)
+ val accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME) ?: intent.getParcelableExtra("account")?.name ?: getSelectedAccountName()
+ accounts.find { it.name.equals(accountName) }?.name
+ }
+
+ if (accountName == null) {
+ Log.w(TAG, "No account, going without!")
+ }
+
+ if (screenId in SCREEN_ID_TO_URL) {
+ val layout = RelativeLayout(this)
+ layout.addView(ProgressBar(this).apply {
+ layoutParams = RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
+ addRule(RelativeLayout.CENTER_HORIZONTAL)
+ addRule(RelativeLayout.CENTER_VERTICAL)
+ }
+ isIndeterminate = true
+ })
+ webView = WebView(this).apply {
+ layoutParams = RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
+ visibility = View.INVISIBLE
+ }
+ layout.addView(webView)
+ setContentView(layout)
+ WebViewHelper(this, webView, ALLOWED_WEB_PREFIXES).openWebView(SCREEN_ID_TO_URL[screenId], accountName)
+ setResult(RESULT_OK)
+ } else {
+ Log.w(TAG, "Unknown screen id, can't open corresponding web page")
+ setResult(RESULT_CANCELED)
+ finish()
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ }
+
+ @Deprecated("Deprecated in Java")
+ override fun onBackPressed() {
+ if (this::webView.isInitialized && webView.canGoBack()) {
+ webView.goBack()
+ } else {
+ super.onBackPressed()
+ }
+ }
+}
\ No newline at end of file
diff --git a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/WebViewHelper.kt b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/WebViewHelper.kt
new file mode 100644
index 00000000..7ce98e9c
--- /dev/null
+++ b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/WebViewHelper.kt
@@ -0,0 +1,130 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.accountsettings.ui
+
+import android.content.Intent
+import android.content.Intent.URI_INTENT_SCHEME
+import android.net.Uri
+import android.util.Log
+import android.view.View
+import android.webkit.WebResourceRequest
+import android.webkit.WebSettings
+import android.webkit.WebView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.lifecycleScope
+import androidx.webkit.WebResourceErrorCompat
+import androidx.webkit.WebViewClientCompat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import org.microg.gms.auth.AuthManager
+import org.microg.gms.common.Constants.GMS_PACKAGE_NAME
+import org.microg.gms.common.PackageUtils
+import java.net.URLEncoder
+import java.util.*
+
+private const val TAG = "AccountSettingsWebView"
+
+class WebViewHelper(private val activity: AppCompatActivity, private val webView: WebView, private val allowedPrefixes: Set = emptySet()) {
+ fun openWebView(url: String?, accountName: String?) {
+ prepareWebViewSettings(webView.settings)
+ webView.webViewClient = object : WebViewClientCompat() {
+ override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceErrorCompat) {
+ Log.w(TAG, "Error loading: $error")
+ }
+
+ override fun onPageFinished(view: WebView?, url: String?) {
+ super.onPageFinished(view, url)
+ webView.visibility = View.VISIBLE
+ }
+
+ @Deprecated("Deprecated in Java")
+ override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
+ Log.d(TAG, "Navigating to $url")
+ if (url.startsWith("intent:")) {
+ try {
+ val intent = Intent.parseUri(url, URI_INTENT_SCHEME)
+ if (intent.`package` == GMS_PACKAGE_NAME || PackageUtils.isGooglePackage(activity, intent.`package`)) {
+ // Only allow to start Google packages
+ activity.startActivity(intent)
+ } else {
+ Log.w(TAG, "Ignoring request to start non-Google app")
+ }
+ } catch (e: Exception) {
+ Log.w(TAG, "Error invoking intent", e)
+ }
+ return false
+ }
+ if (allowedPrefixes.isNotEmpty() && allowedPrefixes.none { url.startsWith(it) }) {
+ try {
+ activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply { addCategory(Intent.CATEGORY_BROWSABLE) })
+ } catch (e: Exception) {
+ Log.w(TAG, "Error forwarding to browser", e)
+ }
+ return true
+ }
+ return false
+ }
+ }
+
+ val urlWithLanguage: String? = addLanguageParam(url)
+ if (accountName != null) {
+ activity.lifecycleScope.launch {
+ withContext(Dispatchers.IO) {
+ openWebWithAccount(accountName, urlWithLanguage)
+ }
+ }
+ } else {
+ loadWebViewUrl(urlWithLanguage)
+ }
+ }
+
+ private fun loadWebViewUrl(url: String?) {
+ if (url != null) {
+ webView.loadUrl(url)
+ } else {
+ activity.finish()
+ }
+ }
+
+ private fun addLanguageParam(url: String?): String? {
+ val language = Locale.getDefault().language
+ return if (language.isNotEmpty()) {
+ Uri.parse(url).buildUpon().appendQueryParameter("hl", language).toString()
+ } else {
+ url
+ }
+ }
+
+ private fun openWebWithAccount(accountName: String, url: String?) {
+ try {
+ val service = "weblogin:continue=" + URLEncoder.encode(url, "utf-8")
+ val authManager = AuthManager(activity, accountName, GMS_PACKAGE_NAME, service)
+ val authUrl = authManager.requestAuth(false)?.auth
+ if (authUrl?.contains("WILL_NOT_SIGN_IN") == true) {
+ throw RuntimeException("Would not sign in")
+ }
+ Log.d(TAG, "Opening $authUrl")
+ webView.post {
+ loadWebViewUrl(authUrl)
+ }
+ } catch (e: Exception) {
+ Log.w(TAG, "Failed to get weblogin auth.", e)
+ activity.finish()
+ }
+ }
+
+ private fun prepareWebViewSettings(settings: WebSettings) {
+ settings.javaScriptEnabled = true
+ settings.setSupportMultipleWindows(false)
+ settings.allowFileAccess = false
+ settings.databaseEnabled = false
+ settings.setNeedInitialFocus(false)
+ settings.useWideViewPort = false
+ settings.setSupportZoom(false)
+ settings.javaScriptCanOpenWindowsAutomatically = false
+ }
+}
\ No newline at end of file
diff --git a/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/extensions.kt b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/extensions.kt
new file mode 100644
index 00000000..5ca88fe7
--- /dev/null
+++ b/play-services-core/src/main/kotlin/org/microg/gms/accountsettings/ui/extensions.kt
@@ -0,0 +1,23 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.accountsettings.ui
+
+const val ACTION_BROWSE_SETTINGS = "com.google.android.gms.accountsettings.action.BROWSE_SETTINGS"
+const val ACTION_MY_ACCOUNT = "com.google.android.gms.accountsettings.MY_ACCOUNT"
+const val ACTION_ACCOUNT_PREFERENCES_SETTINGS = "com.google.android.gms.accountsettings.ACCOUNT_PREFERENCES_SETTINGS"
+const val ACTION_PRIVACY_SETTINGS = "com.google.android.gms.accountsettings.PRIVACY_SETTINGS"
+const val ACTION_SECURITY_SETTINGS = "com.google.android.gms.accountsettings.SECURITY_SETTINGS"
+
+const val EXTRA_CALLING_PACKAGE_NAME = "extra.callingPackageName"
+const val EXTRA_IGNORE_ACCOUNT = "extra.ignoreAccount"
+const val EXTRA_ACCOUNT_NAME = "extra.accountName"
+const val EXTRA_SCREEN_ID = "extra.screenId"
+const val EXTRA_SCREEN_OPTIONS_PREFIX = "extra.screen."
+const val EXTRA_FALLBACK_URL = "extra.fallbackUrl"
+const val EXTRA_FALLBACK_AUTH = "extra.fallbackAuth"
+const val EXTRA_THEME_CHOICE = "extra.themeChoice"
+
+const val OPTION_SCREEN_FLAVOR = "screenFlavor"
\ No newline at end of file
diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/AuthPrefs.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/AuthPrefs.kt
index 5406bf2a..ba5d2b2e 100644
--- a/play-services-core/src/main/kotlin/org/microg/gms/auth/AuthPrefs.kt
+++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/AuthPrefs.kt
@@ -1,8 +1,8 @@
package org.microg.gms.auth
import android.content.Context
-import org.microg.mgms.settings.SettingsContract
-import org.microg.mgms.settings.SettingsContract.Auth
+import org.microg.gms.settings.SettingsContract
+import org.microg.gms.settings.SettingsContract.Auth
object AuthPrefs {
@@ -20,4 +20,11 @@ object AuthPrefs {
}
}
+ @JvmStatic
+ fun shouldIncludeAndroidId(context: Context): Boolean {
+ return SettingsContract.getSettings(context, Auth.getContentUri(context), arrayOf(Auth.INCLUDE_ANDROID_ID)) { c ->
+ c.getInt(0) != 0
+ }
+ }
+
}
diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertManager.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertManager.kt
index 8e5d5036..c99b3cc3 100644
--- a/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertManager.kt
+++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertManager.kt
@@ -29,8 +29,8 @@ import org.microg.gms.gcm.RegisterRequest
import org.microg.gms.gcm.completeRegisterRequest
import org.microg.gms.profile.Build
import org.microg.gms.profile.ProfileManager
-import org.microg.mgms.settings.SettingsContract.CheckIn
-import org.microg.mgms.settings.SettingsContract.getSettings
+import org.microg.gms.settings.SettingsContract.CheckIn
+import org.microg.gms.settings.SettingsContract.getSettings
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import kotlin.random.Random
@@ -97,7 +97,11 @@ class AppCertManager(private val context: Context) {
}
override fun deliverError(error: VolleyError) {
- Log.d(TAG, "Error: ${Base64.encodeToString(error.networkResponse.data, 2)}")
+ if (error.networkResponse != null) {
+ Log.d(TAG, "Error: ${Base64.encodeToString(error.networkResponse.data, 2)}")
+ } else {
+ Log.d(TAG, "Error: ${error.message}")
+ }
deviceKeyCacheTime = 0
deferredResponse.complete(null)
}
@@ -150,11 +154,12 @@ class AppCertManager(private val context: Context) {
)
} else {
Log.d(TAG, "Using fallback spatula header based on Android ID")
- val androidId = getSettings(context, CheckIn.getContentUri(context), arrayOf(CheckIn.ANDROID_ID, CheckIn.SECURITY_TOKEN)) { cursor: Cursor -> cursor.getLong(0) }
+ val androidId = getSettings(context, CheckIn.getContentUri(context), arrayOf(CheckIn.ANDROID_ID)) { cursor: Cursor -> cursor.getLong(0) }
SpatulaHeaderProto(
packageInfo = SpatulaHeaderProto.PackageInfo(packageName, packageCertificateHash),
deviceId = androidId
)
+ return null // TODO
}
Log.d(TAG, "Spatula Header: $proto")
return Base64.encodeToString(proto.encode(), Base64.NO_WRAP)
diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertService.kt
index e73017e2..9b14af49 100644
--- a/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertService.kt
+++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertService.kt
@@ -38,5 +38,5 @@ class AppCertServiceImpl(private val context: Context) : IAppCertService.Stub()
return runBlocking { manager.getSpatulaHeader(packageName) }
}
- override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags) { super.onTransact(code, data, reply, flags) }
+ override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }
}
diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialsService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialsService.kt
index adc0370b..4e933426 100644
--- a/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialsService.kt
+++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialsService.kt
@@ -52,5 +52,5 @@ class CredentialsServiceImpl : ICredentialsService.Stub() {
callbacks.onStatus(Status.SUCCESS)
}
- override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags) { super.onTransact(code, data, reply, flags) }
+ override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }
}
diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/proxy/AuthProxyService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/proxy/AuthProxyService.kt
index e1cedd59..ede33d26 100644
--- a/play-services-core/src/main/kotlin/org/microg/gms/auth/proxy/AuthProxyService.kt
+++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/proxy/AuthProxyService.kt
@@ -59,5 +59,5 @@ class AuthServiceImpl(private val context: Context, private val lifecycle: Lifec
override fun getLifecycle(): Lifecycle = lifecycle
- override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags) { super.onTransact(code, data, reply, flags) }
+ override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }
}
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 51%
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 2953ed60..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 org.microg.mgms.settings.SettingsContract
-import org.microg.mgms.settings.SettingsContract.CheckIn
-import org.microg.mgms.settings.SettingsContract.setSettings
+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/checkin/LastCheckinInfo.kt b/play-services-core/src/main/kotlin/org/microg/gms/checkin/LastCheckinInfo.kt
index b3056893..ab2dc042 100644
--- a/play-services-core/src/main/kotlin/org/microg/gms/checkin/LastCheckinInfo.kt
+++ b/play-services-core/src/main/kotlin/org/microg/gms/checkin/LastCheckinInfo.kt
@@ -16,8 +16,8 @@
package org.microg.gms.checkin
import android.content.Context
-import org.microg.mgms.settings.SettingsContract
-import org.microg.mgms.settings.SettingsContract.CheckIn
+import org.microg.gms.settings.SettingsContract
+import org.microg.gms.settings.SettingsContract.CheckIn
data class LastCheckinInfo(
val lastCheckin: Long,
diff --git a/play-services-core/src/main/kotlin/org/microg/gms/checkin/ServiceInfo.kt b/play-services-core/src/main/kotlin/org/microg/gms/checkin/ServiceInfo.kt
index 1637643b..d42c9e03 100644
--- a/play-services-core/src/main/kotlin/org/microg/gms/checkin/ServiceInfo.kt
+++ b/play-services-core/src/main/kotlin/org/microg/gms/checkin/ServiceInfo.kt
@@ -9,9 +9,9 @@ import android.content.Context
import android.content.Intent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
-import org.microg.mgms.settings.SettingsContract.CheckIn
-import org.microg.mgms.settings.SettingsContract.getSettings
-import org.microg.mgms.settings.SettingsContract.setSettings
+import org.microg.gms.settings.SettingsContract.CheckIn
+import org.microg.gms.settings.SettingsContract.getSettings
+import org.microg.gms.settings.SettingsContract.setSettings
import java.io.Serializable
data class ServiceInfo(val configuration: ServiceConfiguration, val lastCheckin: Long, val androidId: Long) : Serializable
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 b2402779..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
@@ -8,10 +8,11 @@ import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.util.Log
import org.microg.gms.gcm.TriggerReceiver.FORCE_TRY_RECONNECT
-import org.microg.mgms.settings.SettingsContract
-import org.microg.mgms.settings.SettingsContract.Gcm
-import org.microg.mgms.settings.SettingsContract.setSettings
-import org.microg.mgms.settings.SettingsProvider
+import org.microg.gms.settings.SettingsContract
+import org.microg.gms.settings.SettingsContract.Gcm
+import org.microg.gms.settings.SettingsContract.setSettings
+import kotlin.math.max
+import kotlin.math.min
data class GcmPrefs(
val isGcmLogEnabled: Boolean,
@@ -37,6 +38,9 @@ data class GcmPrefs(
const val PREF_NETWORK_ROAMING = Gcm.NETWORK_ROAMING
const val PREF_NETWORK_OTHER = Gcm.NETWORK_OTHER
+ private const val MIN_INTERVAL = 5 * 60 * 1000 // 5 minutes
+ private const val MAX_INTERVAL = 15 * 60 * 1000 // 15 minutes
+
@JvmStatic
fun get(context: Context): GcmPrefs {
return SettingsContract.getSettings(context, Gcm.getContentUri(context), Gcm.PROJECTION) { c ->
@@ -67,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)) {
@@ -75,6 +88,7 @@ data class GcmPrefs(
}
}
+
/**
* Call this whenever the enabled state of GCM has changed.
*/
@@ -88,6 +102,7 @@ data class GcmPrefs(
}
}
+ @Suppress("DEPRECATION")
fun getNetworkPrefForInfo(info: NetworkInfo?): String {
if (info == null) return PREF_NETWORK_OTHER
return if (info.isRoaming) PREF_NETWORK_ROAMING else when (info.type) {
@@ -97,19 +112,20 @@ data class GcmPrefs(
}
}
+ @Suppress("DEPRECATION")
fun getHeartbeatMsFor(info: NetworkInfo?): Int {
return getHeartbeatMsFor(getNetworkPrefForInfo(info))
}
fun getHeartbeatMsFor(pref: String): Int {
return if (PREF_NETWORK_ROAMING == pref) {
- if (networkRoaming != 0) networkRoaming * SettingsProvider.INTERVAL else learntMobileInterval
+ if (networkRoaming != 0) networkRoaming * 60000 else learntMobileInterval
} else if (PREF_NETWORK_MOBILE == pref) {
- if (networkMobile != 0) networkMobile * SettingsProvider.INTERVAL else learntMobileInterval
+ if (networkMobile != 0) networkMobile * 60000 else learntMobileInterval
} else if (PREF_NETWORK_WIFI == pref) {
- if (networkWifi != 0) networkWifi * SettingsProvider.INTERVAL else learntWifiInterval
+ if (networkWifi != 0) networkWifi * 60000 else learntWifiInterval
} else {
- if (networkOther != 0) networkOther * SettingsProvider.INTERVAL else learntOtherInterval
+ if (networkOther != 0) networkOther * 60000 else learntOtherInterval
}
}
@@ -118,15 +134,15 @@ data class GcmPrefs(
when (pref) {
PREF_NETWORK_MOBILE, PREF_NETWORK_ROAMING -> setSettings(context, Gcm.getContentUri(context)) {
val newInterval = (learntMobileInterval * 0.95).toInt()
- put(Gcm.LEARNT_MOBILE, newInterval)
+ put(Gcm.LEARNT_MOBILE, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))
}
PREF_NETWORK_WIFI -> setSettings(context, Gcm.getContentUri(context)) {
- val newInterval = (learntMobileInterval * 0.95).toInt()
- put(Gcm.LEARNT_WIFI, newInterval)
+ val newInterval = (learntWifiInterval * 0.95).toInt()
+ put(Gcm.LEARNT_WIFI, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))
}
else -> setSettings(context, Gcm.getContentUri(context)) {
- val newInterval = (learntMobileInterval * 0.95).toInt()
- put(Gcm.LEARNT_OTHER, newInterval)
+ val newInterval = (learntOtherInterval * 0.95).toInt()
+ put(Gcm.LEARNT_OTHER, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))
}
}
}
@@ -136,28 +152,32 @@ data class GcmPrefs(
when (pref) {
PREF_NETWORK_MOBILE, PREF_NETWORK_ROAMING -> {
if (time > learntMobileInterval / 4 * 3) {
+ val newInterval = (learntMobileInterval * 1.02).toInt()
setSettings(context, Gcm.getContentUri(context)) {
- put(Gcm.LEARNT_MOBILE, SettingsProvider.INTERVAL)
+ put(Gcm.LEARNT_MOBILE, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))
}
}
}
PREF_NETWORK_WIFI -> {
if (time > learntWifiInterval / 4 * 3) {
+ val newInterval = (learntWifiInterval * 1.02).toInt()
setSettings(context, Gcm.getContentUri(context)) {
- put(Gcm.LEARNT_WIFI, SettingsProvider.INTERVAL)
+ put(Gcm.LEARNT_WIFI, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))
}
}
}
else -> {
if (time > learntOtherInterval / 4 * 3) {
+ val newInterval = (learntOtherInterval * 1.02).toInt()
setSettings(context, Gcm.getContentUri(context)) {
- put(Gcm.LEARNT_OTHER, SettingsProvider.INTERVAL)
+ put(Gcm.LEARNT_OTHER, max(MIN_INTERVAL, min(newInterval, MAX_INTERVAL)))
}
}
}
}
}
+ @Suppress("DEPRECATION")
fun isEnabledFor(info: NetworkInfo?): Boolean {
return isEnabled && info != null && getHeartbeatMsFor(info) >= 0
}
@@ -168,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 d3e519bd..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 ->
@@ -51,7 +51,7 @@ private suspend fun ensureCheckinIsUpToDate(context: Context) {
}
}
-private suspend fun ensureAppRegistrationAllowed(context: Context, database: GcmDatabase, packageName: String) {
+private fun ensureAppRegistrationAllowed(context: Context, database: GcmDatabase, packageName: String) {
if (!GcmPrefs.get(context).isEnabled) throw RuntimeException("GCM disabled")
val app = database.getApp(packageName)
if (app?.allowRegister == false) {
@@ -65,7 +65,7 @@ suspend fun completeRegisterRequest(context: Context, database: GcmDatabase, req
private val Intent.requestId: String?
get() {
- val kidString = getStringExtra(GcmConstants.EXTRA_KID) ?: return null
+ val kidString = getStringExtra(EXTRA_KID) ?: return null
if (kidString.startsWith("|")) {
val kid = kidString.split("\\|".toRegex()).toTypedArray()
if (kid.size >= 3 && "ID" == kid[1]) {
@@ -245,7 +245,7 @@ internal class PushRegisterHandler(private val context: Context, private val dat
get() {
val intent = Intent()
intent.setPackage("com.google.example.invalidpackage")
- return PendingIntent.getBroadcast(context, 0, intent, 0)
+ return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
}
override fun handleMessage(msg: Message) {
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 ef30f876..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,10 +11,10 @@ import android.util.DisplayMetrics
import android.widget.ImageView
import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder
+import android.content.pm.ApplicationInfo
-class AppIconPreference : Preference {
- constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(
- context, attrs, defStyleAttr, defStyleRes)
+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)
constructor(context: Context) : super(context)
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 a0b4ad13..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