diff --git a/build.gradle b/build.gradle index c38d74493855e2385cdbe128e1f94fb9bed8b5ce..cfb1200724fb105d55fbbffec3c5a2e56c8b8c7b 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,7 @@ */ buildscript { + ext.cronetVersion = '91.0.4472.120' ext.nlpVersion = '2.0-alpha6' ext.remoteDroidGuardVersion = '0.1.2' ext.safeParcelVersion = '1.7.0' @@ -58,7 +59,7 @@ def execResult(...args) { return stdout.toString().trim() } -def gmsVersion = "21.15.15" +def gmsVersion = "21.21.58" def gmsVersionCode = Integer.parseInt(gmsVersion.replaceAll('\\.', '')) def gitVersionBase = execResult('git', 'describe', '--tags', '--abbrev=0', '--match=v[0-9]*').substring(1) def gitCommitCount = Integer.parseInt(execResult('git', 'rev-list', '--count', "v$gitVersionBase..HEAD")) 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 75a949b856132e2afc4f34a2a90531b6f6c80289..3bc93136a80bccabdfba1702569da322f65141c2 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 @@ -9,6 +9,9 @@ import com.google.android.gms.auth.AccountChangeEventsRequest; interface IAuthManagerService { Bundle getToken(String accountName, String scope, in Bundle extras) = 0; Bundle clearToken(String token, in Bundle extras) = 1; - AccountChangeEventsResponse getChangeEvents(in AccountChangeEventsRequest request) = 2; + AccountChangeEventsResponse getChangeEvents(in AccountChangeEventsRequest request) = 2; Bundle getTokenWithAccount(in Account account, String scope, in Bundle extras) = 4; + Bundle getAccounts(in Bundle extras) = 5; + Bundle removeAccount(in Account account) = 6; + Bundle requestGoogleAccountsAccess(String packageName) = 7; } diff --git a/play-services-api/src/main/aidl/com/google/android/gms/dynamite/IDynamiteLoader.aidl b/play-services-api/src/main/aidl/com/google/android/gms/dynamite/IDynamiteLoader.aidl index 8cb2be99f136b29a5d245971b955b86ac4ce8f07..017a2dc276e19454b18ee76322f94758ebff6b77 100644 --- a/play-services-api/src/main/aidl/com/google/android/gms/dynamite/IDynamiteLoader.aidl +++ b/play-services-api/src/main/aidl/com/google/android/gms/dynamite/IDynamiteLoader.aidl @@ -3,8 +3,12 @@ package com.google.android.gms.dynamite; import com.google.android.gms.dynamic.IObjectWrapper; interface IDynamiteLoader { - int getModuleVersion(IObjectWrapper context, String moduleId) = 0; - int getModuleVersion2(IObjectWrapper context, String moduleId, boolean updateConfigIfRequired) = 2; + int getModuleVersion(IObjectWrapper wrappedContext, String moduleId) = 0; + int getModuleVersion2(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) = 2; + int getModuleVersion2NoCrashUtils(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) = 4; - IObjectWrapper createModuleContext(IObjectWrapper context, String moduleId, int minVersion) = 1; -} \ No newline at end of file + IObjectWrapper createModuleContext(IObjectWrapper wrappedContext, String moduleId, int minVersion) = 1; + IObjectWrapper createModuleContextNoCrashUtils(IObjectWrapper wrappedContext, String moduleId, int minVersion) = 3; + + int getIDynamiteLoaderVersion() = 5; +} diff --git a/play-services-api/src/main/aidl/com/google/android/gms/tapandpay/internal/ITapAndPayService.aidl b/play-services-api/src/main/aidl/com/google/android/gms/tapandpay/internal/ITapAndPayService.aidl deleted file mode 100644 index 622b0ba78cf153f1c884fa66bedbfc6428a38989..0000000000000000000000000000000000000000 --- a/play-services-api/src/main/aidl/com/google/android/gms/tapandpay/internal/ITapAndPayService.aidl +++ /dev/null @@ -1,5 +0,0 @@ -package com.google.android.gms.tapandpay.internal; - -interface ITapAndPayService { - -} diff --git a/play-services-api/src/main/java/com/google/android/gms/auth/api/credentials/CredentialRequest.java b/play-services-api/src/main/java/com/google/android/gms/auth/api/credentials/CredentialRequest.java index 9a5fa917169680ec71ae8a68a18bae5271d095ee..a1679445473d87fe419aeb04085df90b19fe39ad 100644 --- a/play-services-api/src/main/java/com/google/android/gms/auth/api/credentials/CredentialRequest.java +++ b/play-services-api/src/main/java/com/google/android/gms/auth/api/credentials/CredentialRequest.java @@ -29,6 +29,8 @@ public class CredentialRequest extends AutoSafeParcelable { @Field(4) private CredentialPickerConfig credentialHintPickerConfig; + private CredentialRequest() { } + public CredentialRequest(boolean passwordLoginSupported, String[] accountTypes, CredentialPickerConfig credentialPickerConfig, CredentialPickerConfig credentialHintPickerConfig) { this.passwordLoginSupported = passwordLoginSupported; this.accountTypes = accountTypes; diff --git a/play-services-api/src/main/java/com/google/android/gms/wallet/IsReadyToPayRequest.java b/play-services-api/src/main/java/com/google/android/gms/wallet/IsReadyToPayRequest.java index 5af035412410a3137cf55cfb0085cb733a28480a..2f9fde8bf6f579415b6ab4777f7f5f71d13fbe35 100644 --- a/play-services-api/src/main/java/com/google/android/gms/wallet/IsReadyToPayRequest.java +++ b/play-services-api/src/main/java/com/google/android/gms/wallet/IsReadyToPayRequest.java @@ -19,13 +19,13 @@ import java.util.Collection; */ @PublicApi public class IsReadyToPayRequest extends AutoSafeParcelable { - @Field(2) + @Field(value = 2, useDirectList = true) private ArrayList allowedCardNetworks; @Field(4) private String unknown4; @Field(5) private String unknown5; - @Field(6) + @Field(value = 6, useDirectList = true) private ArrayList allowedPaymentMethods; @Field(7) private boolean existingPaymentMethodRequired; diff --git a/play-services-base-core/build.gradle b/play-services-base-core/build.gradle index e6d2818a20882b919fce9daa798da35756d0f06c..9e9dd1b60fbc4855274780063634a2bfa8bb4845 100644 --- a/play-services-base-core/build.gradle +++ b/play-services-base-core/build.gradle @@ -9,9 +9,9 @@ apply plugin: 'signing' dependencies { api project(':play-services-basement') + api "androidx.lifecycle:lifecycle-service:$lifecycleVersion" implementation "androidx.annotation:annotation:$annotationVersion" - implementation "androidx.lifecycle:lifecycle-service:$lifecycleVersion" } android { diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/api/CommonStatusCodes.java b/play-services-basement/src/main/java/com/google/android/gms/common/api/CommonStatusCodes.java index 6a2cbb519464a8711a51d873bd2e24364eb65222..708a1e29d57bdd39d6af25b497ea50ded4a758dc 100644 --- a/play-services-basement/src/main/java/com/google/android/gms/common/api/CommonStatusCodes.java +++ b/play-services-basement/src/main/java/com/google/android/gms/common/api/CommonStatusCodes.java @@ -20,6 +20,7 @@ import androidx.annotation.NonNull; import org.microg.gms.common.PublicApi; +@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"}) @PublicApi public class CommonStatusCodes { public static final int SUCCESS_CACHE = -1; diff --git a/play-services-basement/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt b/play-services-basement/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt new file mode 100644 index 0000000000000000000000000000000000000000..cb87e5ebbdd1833bef6e97dac2291cf3d595cdb9 --- /dev/null +++ b/play-services-basement/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt @@ -0,0 +1,120 @@ +package org.microg.gms.settings + +import android.content.ContentValues +import android.content.Context +import android.database.Cursor +import android.net.Uri + +object SettingsContract { + const val AUTHORITY = "org.microg.gms.settings" + val AUTHORITY_URI: Uri = Uri.parse("content://$AUTHORITY") + + object CheckIn { + private const val id = "check-in" + val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id) + const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id" + + const val ENABLED = "checkin_enable_service" + const val ANDROID_ID = "androidId" + const val DIGEST = "digest" + const val LAST_CHECK_IN = "lastCheckin" + const val SECURITY_TOKEN = "securityToken" + const val VERSION_INFO = "versionInfo" + const val DEVICE_DATA_VERSION_INFO = "deviceDataVersionInfo" + + val PROJECTION = arrayOf( + ENABLED, + ANDROID_ID, + DIGEST, + LAST_CHECK_IN, + SECURITY_TOKEN, + VERSION_INFO, + DEVICE_DATA_VERSION_INFO, + ) + const val PREFERENCES_NAME = "checkin" + const val INITIAL_DIGEST = "1-929a0dca0eee55513280171a8585da7dcd3700f8" + } + + object Gcm { + private const val id = "gcm" + val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id) + const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id" + + const val FULL_LOG = "gcm_full_log" + const val LAST_PERSISTENT_ID = "gcm_last_persistent_id" + const val CONFIRM_NEW_APPS = "gcm_confirm_new_apps" + const val ENABLE_GCM = "gcm_enable_mcs_service" + + const val NETWORK_MOBILE = "gcm_network_mobile" + const val NETWORK_WIFI = "gcm_network_wifi" + const val NETWORK_ROAMING = "gcm_network_roaming" + const val NETWORK_OTHER = "gcm_network_other" + + const val LEARNT_MOBILE = "gcm_learnt_mobile" + const val LEARNT_WIFI = "gcm_learnt_wifi" + const val LEARNT_OTHER = "gcm_learnt_other" + + val PROJECTION = arrayOf( + FULL_LOG, + LAST_PERSISTENT_ID, + CONFIRM_NEW_APPS, + ENABLE_GCM, + NETWORK_MOBILE, + NETWORK_WIFI, + NETWORK_ROAMING, + NETWORK_OTHER, + LEARNT_MOBILE, + LEARNT_WIFI, + LEARNT_OTHER, + ) + } + + object Auth { + private const val id = "auth" + val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id) + const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id" + + const val TRUST_GOOGLE = "auth_manager_trust_google" + const val VISIBLE = "auth_manager_visible" + + val PROJECTION = arrayOf( + TRUST_GOOGLE, + VISIBLE, + ) + } + + object Exposure { + private const val id = "exposureNotification" + val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id) + const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id" + + const val SCANNER_ENABLED = "exposure_scanner_enabled" + const val LAST_CLEANUP = "exposure_last_cleanup" + + val PROJECTION = arrayOf( + SCANNER_ENABLED, + LAST_CLEANUP, + ) + } + + object SafetyNet { + private const val id = "safety-net" + val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id) + const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id" + } + + fun getSettings(context: Context, uri: Uri, projection: Array?, f: (Cursor) -> T): T { + context.contentResolver.query(uri, projection, null, null, null).use { c -> + require(c != null) { "Cursor for query $uri ${projection?.toList()} was null" } + if (!c.moveToFirst()) error("Cursor for query $uri ${projection?.toList()} was empty") + return f.invoke(c) + } + } + + fun setSettings(context: Context, uri: Uri, v: ContentValues.() -> Unit) { + val values = ContentValues().apply { v.invoke(this) } + val affected = context.contentResolver.update(uri, values, null, null) + require(affected == 1) { "Update for $uri with $values affected 0 rows"} + } + +} diff --git a/play-services-core/build.gradle b/play-services-core/build.gradle index 89edd7055e19f4a66eae2f78176c29a9a07049a9..c06fd159bbdad9a64b124c27d4832cd50fd514e3 100644 --- a/play-services-core/build.gradle +++ b/play-services-core/build.gradle @@ -43,10 +43,13 @@ dependencies { implementation project(':play-services-base-core') implementation project(':play-services-base-core-ui') implementation project(':play-services-conscrypt-provider-core') + implementation project(':play-services-cronet-core') implementation project(':play-services-location-core') - implementation project(':play-services-vision-core') withNearbyImplementation project(':play-services-nearby-core') withNearbyImplementation project(':play-services-nearby-core-ui') + implementation project(':play-services-tapandpay-core') + implementation project(':play-services-vision-core') + implementation project(':play-services-core-proto') implementation project(':play-services-core:microg-ui-tools') // deprecated implementation project(':play-services-api') diff --git a/play-services-core/src/main/AndroidManifest.xml b/play-services-core/src/main/AndroidManifest.xml index 844bae888a320159fc9a2534f17a79b633da5426..5543e0d1960b0ad14ded0e70a1f97f6b9304c8c9 100644 --- a/play-services-core/src/main/AndroidManifest.xml +++ b/play-services-core/src/main/AndroidManifest.xml @@ -114,6 +114,7 @@ android:fullBackupOnly="true" android:extractNativeLibs="false" android:forceQueryable="true" + android:persistent="true" android:icon="@mipmap/ic_core_service_app" android:label="@string/gms_app_name" android:theme="@style/Theme.AppCompat.DayNight"> @@ -128,6 +129,13 @@ android:exported="true" android:permission="org.microg.gms.PROVISION" /> + + + + - - @@ -422,7 +428,7 @@ android:exported="true" /> @@ -430,6 +436,12 @@ + + + + + + @@ -463,6 +475,12 @@ android:authorities="com.google.android.gms.chimera" android:exported="true" /> + + + - - - - - @@ -733,7 +746,6 @@ - diff --git a/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteContext.java b/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteContext.java new file mode 100644 index 0000000000000000000000000000000000000000..8484447b2b03cf1ebea6df39cdb2a63b034c295a --- /dev/null +++ b/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteContext.java @@ -0,0 +1,97 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.chimera.container; + +import android.content.Context; +import android.content.ContextWrapper; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Process; +import android.util.Log; + +import androidx.annotation.RequiresApi; + +import org.microg.gms.common.Constants; + +import java.io.File; + +import dalvik.system.PathClassLoader; + +public class DynamiteContext extends ContextWrapper { + private static final String TAG = "DynamiteContext"; + private DynamiteModuleInfo moduleInfo; + private Context originalContext; + private Context gmsContext; + private DynamiteContext appContext; + + private ClassLoader classLoader; + + public DynamiteContext(DynamiteModuleInfo moduleInfo, Context base, Context gmsContext, DynamiteContext appContext) { + super(base); + this.moduleInfo = moduleInfo; + this.originalContext = base; + this.gmsContext = gmsContext; + this.appContext = appContext; + } + + @Override + public ClassLoader getClassLoader() { + if (classLoader == null) { + StringBuilder nativeLoaderDirs = new StringBuilder(gmsContext.getApplicationInfo().nativeLibraryDir); + if (Build.VERSION.SDK_INT >= 23 && Process.is64Bit()) { + for (String abi : Build.SUPPORTED_64_BIT_ABIS) { + nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(abi); + } + } else if (Build.VERSION.SDK_INT >= 21) { + for (String abi : Build.SUPPORTED_32_BIT_ABIS) { + nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(abi); + } + } else { + nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(Build.CPU_ABI); + } + classLoader = new PathClassLoader(gmsContext.getApplicationInfo().sourceDir, nativeLoaderDirs.toString(), new FilteredClassLoader(originalContext.getClassLoader(), moduleInfo.getMergedClasses(), moduleInfo.getMergedPackages())); + } + return classLoader; + } + + @Override + public String getPackageName() { + return gmsContext.getPackageName(); + } + + @Override + public ApplicationInfo getApplicationInfo() { + return gmsContext.getApplicationInfo(); + } + + @Override + public Context getApplicationContext() { + return appContext; + } + + @RequiresApi(24) + @Override + public Context createDeviceProtectedStorageContext() { + return new DynamiteContext(moduleInfo, originalContext.createDeviceProtectedStorageContext(), gmsContext.createDeviceProtectedStorageContext(), appContext); + } + + public static DynamiteContext create(String moduleId, Context originalContext) { + try { + DynamiteModuleInfo moduleInfo = new DynamiteModuleInfo(moduleId); + Context gmsContext = originalContext.createPackageContext(Constants.GMS_PACKAGE_NAME, 0); + Context originalAppContext = originalContext.getApplicationContext(); + if (originalAppContext == null || originalAppContext == originalContext) { + return new DynamiteContext(moduleInfo, originalContext, gmsContext, null); + } else { + return new DynamiteContext(moduleInfo, originalContext, gmsContext, new DynamiteContext(moduleInfo, originalAppContext, gmsContext, null)); + } + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, e); + return null; + } + } +} diff --git a/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteLoaderImpl.java b/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteLoaderImpl.java index d4a272af2ca79f8ce43edfd0675c6a350b421a67..e27537d38620c48d4d84649106ff48340a269109 100644 --- a/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteLoaderImpl.java +++ b/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteLoaderImpl.java @@ -35,28 +35,41 @@ public class DynamiteLoaderImpl extends IDynamiteLoader.Stub { @Override public IObjectWrapper createModuleContext(IObjectWrapper wrappedContext, String moduleId, int minVersion) throws RemoteException { + // We don't have crash utils, so just forward + return createModuleContextNoCrashUtils(wrappedContext, moduleId, minVersion); + } + + @Override + public IObjectWrapper createModuleContextNoCrashUtils(IObjectWrapper wrappedContext, String moduleId, int minVersion) throws RemoteException { Log.d(TAG, "createModuleContext for " + moduleId + " at version " + minVersion); - final Context context = (Context) ObjectWrapper.unwrap(wrappedContext); - try { - return ObjectWrapper.wrap(new ContextWrapper(context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY)) { - @Override - public Context getApplicationContext() { - return context; - } - }); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "returning null instead", e); - return null; - } + final Context originalContext = (Context) ObjectWrapper.unwrap(wrappedContext); + return ObjectWrapper.wrap(DynamiteContext.create(moduleId, originalContext)); } @Override - public int getModuleVersion(IObjectWrapper context, String moduleId) throws RemoteException { - return getModuleVersion2(context, moduleId, true); + public int getIDynamiteLoaderVersion() throws RemoteException { + return 2; } @Override - public int getModuleVersion2(IObjectWrapper context, String moduleId, boolean updateConfigIfRequired) throws RemoteException { + public int getModuleVersion(IObjectWrapper wrappedContext, String moduleId) throws RemoteException { + return getModuleVersion2(wrappedContext, moduleId, true); + } + + @Override + public int getModuleVersion2(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) throws RemoteException { + // We don't have crash utils, so just forward + return getModuleVersion2NoCrashUtils(wrappedContext, moduleId, updateConfigIfRequired); + } + + @Override + public int getModuleVersion2NoCrashUtils(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) throws RemoteException { + final Context context = (Context) ObjectWrapper.unwrap(wrappedContext); + if (context == null) { + Log.w(TAG, "Invalid client context"); + return 0; + } + try { return Class.forName("com.google.android.gms.dynamite.descriptors." + moduleId + ".ModuleDescriptor").getDeclaredField("MODULE_VERSION").getInt(null); } catch (Exception e) { diff --git a/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteModuleInfo.java b/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteModuleInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..637a269fcae3e29de3bf165974adab025f286013 --- /dev/null +++ b/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteModuleInfo.java @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.chimera.container; + +import java.util.Collection; +import java.util.Collections; + +import static android.content.Context.CONTEXT_IGNORE_SECURITY; +import static android.content.Context.CONTEXT_INCLUDE_CODE; + +public class DynamiteModuleInfo { + private Class descriptor; + private String moduleId; + + public DynamiteModuleInfo(String moduleId) { + this.moduleId = moduleId; + try { + this.descriptor = Class.forName("com.google.android.gms.dynamite.descriptors." + moduleId + ".ModuleDescriptor"); + } catch (Exception e) { + // Ignore + } + } + + public String getModuleId() { + return moduleId; + } + + public int getVersion() { + try { + return descriptor.getDeclaredField("MODULE_VERSION").getInt(null); + } catch (Exception e) { + return 0; + } + } + + public Collection getMergedPackages() { + try { + return (Collection) descriptor.getDeclaredField("MERGED_PACKAGES").get(null); + } catch (Exception e) { + return Collections.emptySet(); + } + } + + public Collection getMergedClasses() { + try { + return (Collection) descriptor.getDeclaredField("MERGED_CLASSES").get(null); + } catch (Exception e) { + return Collections.emptySet(); + } + } +} diff --git a/play-services-core/src/main/java/com/google/android/gms/chimera/container/FilteredClassLoader.java b/play-services-core/src/main/java/com/google/android/gms/chimera/container/FilteredClassLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..76731fc3d1ab5c49247362f096b58d1d8c700678 --- /dev/null +++ b/play-services-core/src/main/java/com/google/android/gms/chimera/container/FilteredClassLoader.java @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.chimera.container; + +import android.util.Log; + +import java.util.Collection; +import java.util.HashSet; + +public class FilteredClassLoader extends ClassLoader { + private static ClassLoader rootClassLoader; + private final Collection allowedClasses; + private final Collection allowedPackages; + + static { + rootClassLoader = ClassLoader.getSystemClassLoader(); + if (rootClassLoader == null) { + rootClassLoader = FilteredClassLoader.class.getClassLoader(); + while (rootClassLoader.getParent() != null) { + rootClassLoader = rootClassLoader.getParent(); + } + } + } + + public FilteredClassLoader(ClassLoader parent, Collection allowedClasses, Collection allowedPackages) { + super(parent); + this.allowedClasses = new HashSet<>(allowedClasses); + this.allowedPackages = new HashSet<>(allowedPackages); + } + + private String getPackageName(String name) { + int lastIndex = name.lastIndexOf("."); + if (lastIndex <= 0) return ""; + return name.substring(0, lastIndex); + } + + private String getClassName(String name) { + int lastIndex = name.indexOf("$"); + if (lastIndex <= 0) return name; + return name.substring(0, lastIndex); + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (name.startsWith("java.")) return rootClassLoader.loadClass(name); + if (allowedClasses.contains(name) || allowedClasses.contains(getClassName(name))) + return super.loadClass(name, resolve); + if (allowedClasses.contains("!" + name) || allowedClasses.contains("!" + getClassName(name))) + return rootClassLoader.loadClass(name); + if (allowedPackages.contains(getPackageName(name))) return super.loadClass(name, resolve); + return rootClassLoader.loadClass(name); + } +} 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 deb2acbf09a83ed49acd746624ac319d1312d113..5b8282cf9c6d78076bbf1b7f6aff68d82546d9b1 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 @@ -21,22 +21,22 @@ import android.accounts.AccountManager; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; -import android.preference.PreferenceManager; import android.util.Log; import org.microg.gms.common.PackageUtils; +import org.microg.gms.settings.SettingsContract; import java.io.IOException; import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; +import static org.microg.gms.auth.AuthPrefs.isTrustGooglePermitted; public class AuthManager { private static final String TAG = "GmsAuthManager"; public static final String PERMISSION_TREE_BASE = "com.google.android.googleapps.permission.GOOGLE_AUTH."; - private static final String PREF_AUTH_TRUST_GOOGLE = "auth_manager_trust_google"; - public static final String PREF_AUTH_VISIBLE = "auth_manager_visible"; + public static final String PREF_AUTH_VISIBLE = SettingsContract.Auth.VISIBLE; public static final int ONE_HOUR_IN_SECONDS = 60 * 60; private final Context context; @@ -185,14 +185,6 @@ public class AuthManager { } } - public static boolean isTrustGooglePermitted(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_AUTH_TRUST_GOOGLE, true); - } - - public static boolean isAuthVisible(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_AUTH_VISIBLE, false); - } - private boolean isSystemApp() { try { int flags = context.getPackageManager().getApplicationInfo(packageName, 0).flags; 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 0639fe03362c42fb8d6a00bb5612a815bcf79ace..b272227054794721054c20434f1f795c8509a523 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,6 +18,8 @@ package org.microg.gms.auth; import android.accounts.Account; import android.accounts.AccountManager; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; @@ -43,7 +45,9 @@ import org.microg.gms.common.PackageUtils; import java.io.IOException; import java.util.ArrayList; 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; @@ -53,6 +57,7 @@ import static org.microg.gms.auth.AskPermissionActivity.EXTRA_CONSENT_DATA; public class AuthManagerServiceImpl extends IAuthManagerService.Stub { private static final String TAG = "GmsAuthManagerSvc"; + public static final String KEY_ACCOUNT_FEATURES = "account_features"; public static final String KEY_AUTHORITY = "authority"; public static final String KEY_CALLBACK_INTENT = "callback_intent"; public static final String KEY_CALLER_UID = "callerUid"; @@ -74,14 +79,42 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub { } @Override - public Bundle getToken(String accountName, String scope, Bundle extras) throws RemoteException { + public Bundle getToken(String accountName, String scope, Bundle extras) { + return getTokenWithAccount(new Account(accountName, AuthConstants.DEFAULT_ACCOUNT_TYPE), scope, extras); + } + + private List getScopes(String scope) { + if (!scope.startsWith("oauth2:")) return null; + String[] strings = scope.substring(7).split(" "); + List res = new ArrayList(); + for (String string : strings) { + res.add(new Scope(string)); + } + return res; + } + + private static CharSequence getPackageLabel(String packageName, PackageManager pm) { + try { + return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)); + } catch (PackageManager.NameNotFoundException e) { + return packageName; + } + } + + @Override + public AccountChangeEventsResponse getChangeEvents(AccountChangeEventsRequest request) { + return new AccountChangeEventsResponse(); + } + + @Override + public Bundle getTokenWithAccount(Account account, String scope, Bundle extras) { String packageName = extras.getString(KEY_ANDROID_PACKAGE_NAME); if (packageName == null || packageName.isEmpty()) packageName = extras.getString(KEY_CLIENT_PACKAGE_NAME); 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:" + accountName + " scope:" + scope + " extras:" + extras + ", notify: " + notify); + 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/), @@ -89,9 +122,9 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub { */ scope = scope.replace("https://www.googleapis.com/auth/identity.plus.page.impersonation ", ""); - AuthManager authManager = new AuthManager(context, accountName, packageName, scope); + AuthManager authManager = new AuthManager(context, account.name, packageName, scope); Bundle result = new Bundle(); - result.putString(KEY_ACCOUNT_NAME, accountName); + result.putString(KEY_ACCOUNT_NAME, account.name); result.putString(KEY_ACCOUNT_TYPE, authManager.getAccountType()); if (!authManager.accountExists()) { result.putString(KEY_ERROR, "NetworkError"); @@ -112,7 +145,7 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub { i.putExtras(extras); i.putExtra(KEY_ANDROID_PACKAGE_NAME, packageName); i.putExtra(KEY_ACCOUNT_TYPE, authManager.getAccountType()); - i.putExtra(KEY_ACCOUNT_NAME, accountName); + i.putExtra(KEY_ACCOUNT_NAME, account.name); i.putExtra(KEY_AUTHTOKEN, scope); try { if (res.consentDataBase64 != null) @@ -138,36 +171,41 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub { return result; } - private List getScopes(String scope) { - if (!scope.startsWith("oauth2:")) return null; - String[] strings = scope.substring(7).split(" "); - List res = new ArrayList(); - for (String string : strings) { - res.add(new Scope(string)); + @Override + public Bundle getAccounts(Bundle extras) { + PackageUtils.assertExtendedAccess(context); + String[] accountFeatures = extras.getStringArray(KEY_ACCOUNT_FEATURES); + String accountType = extras.getString(KEY_ACCOUNT_TYPE); + Account[] accounts; + if (accountFeatures != null) { + try { + accounts = AccountManager.get(context).getAccountsByTypeAndFeatures(accountType, accountFeatures, null, null).getResult(5, TimeUnit.SECONDS); + } catch (Exception e) { + Log.w(TAG, e); + return null; + } + } else { + accounts = AccountManager.get(context).getAccountsByType(accountType); } + Bundle res = new Bundle(); + res.putParcelableArray(KEY_ACCOUNTS, accounts); return res; } - private static CharSequence getPackageLabel(String packageName, PackageManager pm) { - try { - return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)); - } catch (PackageManager.NameNotFoundException e) { - return packageName; - } - } - @Override - public AccountChangeEventsResponse getChangeEvents(AccountChangeEventsRequest request) { - return new AccountChangeEventsResponse(); + public Bundle removeAccount(Account account) { + Log.w(TAG, "Not implemented: removeAccount(" + account + ")"); + return null; } @Override - public Bundle getTokenWithAccount(Account account, String scope, Bundle extras) throws RemoteException { - return getToken(account.name, scope, extras); + public Bundle requestGoogleAccountsAccess(String packageName) throws RemoteException { + Log.w(TAG, "Not implemented: requestGoogleAccountsAccess(" + packageName + ")"); + return null; } @Override - public Bundle clearToken(String token, Bundle extras) throws RemoteException { + public Bundle clearToken(String token, Bundle extras) { String packageName = extras.getString(KEY_ANDROID_PACKAGE_NAME); if (packageName == null) packageName = extras.getString(KEY_CLIENT_PACKAGE_NAME); packageName = PackageUtils.getAndCheckCallingPackage(context, packageName, extras.getInt(KEY_CALLER_UID, 0), extras.getInt(KEY_CALLER_PID, 0)); 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 8365adb9fa46ad16ea50269bde5032fe7b8da779..8dda8e4c871bbde2f434fc65a68dcb8f9f5341fb 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,7 @@ public class AuthRequest extends HttpFormClient.Request { public AuthRequest fromContext(Context context) { build(Utils.getBuild(context)); locale(Utils.getLocale(context)); - androidIdHex = Long.toHexString(LastCheckinInfo.read(context).androidId); + 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 13a26b2e4fa93699bd724d0104b3143cbefe44c3..94706145355dead5b436cfc42a80d99423dd654c 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 @@ -21,7 +21,6 @@ import android.accounts.AccountManager; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; -import android.graphics.Bitmap; import android.graphics.Color; import android.net.ConnectivityManager; import android.net.NetworkInfo; @@ -36,7 +35,6 @@ import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.webkit.CookieManager; import android.webkit.JavascriptInterface; -import android.webkit.ValueCallback; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; @@ -72,6 +70,7 @@ import static android.view.KeyEvent.KEYCODE_BACK; 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.common.Constants.GMS_PACKAGE_NAME; import static org.microg.gms.common.Constants.GMS_VERSION_CODE; @@ -136,7 +135,7 @@ public class LoginActivity extends AssistantActivity { AccountManager accountManager = AccountManager.get(this); Account account = new Account(getIntent().getStringExtra(EXTRA_EMAIL), accountType); accountManager.addAccountExplicitly(account, getIntent().getStringExtra(EXTRA_TOKEN), null); - if (AuthManager.isAuthVisible(this) && SDK_INT >= Build.VERSION_CODES.O) { + if (isAuthVisible(this) && SDK_INT >= Build.VERSION_CODES.O) { accountManager.setAccountVisibility(account, PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, VISIBILITY_USER_MANAGED_VISIBLE); } retrieveGmsToken(account); @@ -223,7 +222,7 @@ public class LoginActivity extends AssistantActivity { ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = cm.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isConnected()) { - if (LastCheckinInfo.read(this).androidId == 0) { + if (LastCheckinInfo.read(this).getAndroidId() == 0) { new Thread(() -> { Runnable next; next = checkin(false) ? this::loadLoginPage : () -> showError(R.string.auth_general_error_desc); @@ -425,7 +424,7 @@ public class LoginActivity extends AssistantActivity { @JavascriptInterface public final String getAndroidId() { - long androidId = LastCheckinInfo.read(LoginActivity.this).androidId; + long androidId = LastCheckinInfo.read(LoginActivity.this).getAndroidId(); Log.d(TAG, "JSBridge: getAndroidId " + androidId); if (androidId == 0 || androidId == -1) return null; return Long.toHexString(androidId); 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 3ecc09994eadbd6d2a473738028274ea59afc6df..0b56919fc33eabc352b179fbaba23e833869c14a 100644 --- 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 @@ -18,15 +18,12 @@ package org.microg.gms.checkin; import android.util.Log; -import com.squareup.wire.Wire; - import org.microg.gms.common.Build; import org.microg.gms.common.DeviceConfiguration; import org.microg.gms.common.DeviceIdentifier; import org.microg.gms.common.PhoneInfo; import org.microg.gms.common.Utils; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -46,8 +43,8 @@ import java.util.zip.GZIPOutputStream; public class CheckinClient { private static final String TAG = "GmsCheckinClient"; private static final Object TODO = null; // TODO - private static final List TODO_LIST_STRING = new ArrayList(); // TODO - private static final List TODO_LIST_CHECKIN = new ArrayList(); // TODO + private static final List TODO_LIST_STRING = new ArrayList<>(); // TODO + private static final List TODO_LIST_CHECKIN = new ArrayList<>(); // TODO private static final String SERVICE_URL = "https://android.clients.google.com/checkin"; public static CheckinResponse request(CheckinRequest request) throws IOException { @@ -84,8 +81,8 @@ public class CheckinClient { LastCheckinInfo checkinInfo, Locale locale, List accounts) { CheckinRequest.Builder builder = new CheckinRequest.Builder() - .accountCookie(new ArrayList()) - .androidId(checkinInfo.androidId) + .accountCookie(new ArrayList<>()) + .androidId(checkinInfo.getAndroidId()) .checkin(new CheckinRequest.Checkin.Builder() .build(new CheckinRequest.Checkin.Build.Builder() .bootloader(build.bootloader) @@ -105,11 +102,11 @@ public class CheckinClient { .build()) .cellOperator(phoneInfo.cellOperator) .event(Collections.singletonList(new CheckinRequest.Checkin.Event.Builder() - .tag(checkinInfo.androidId == 0 ? "event_log_start" : "system_update") - .value(checkinInfo.androidId == 0 ? null : "1536,0,-1,NULL") + .tag(checkinInfo.getAndroidId() == 0 ? "event_log_start" : "system_update") + .value(checkinInfo.getAndroidId() == 0 ? null : "1536,0,-1,NULL") .timeMs(new Date().getTime()) .build())) - .lastCheckinMs(checkinInfo.lastCheckin) + .lastCheckinMs(checkinInfo.getLastCheckin()) .requestedGroup(TODO_LIST_STRING) .roaming(phoneInfo.roaming) .simOperator(phoneInfo.simOperator) @@ -133,7 +130,7 @@ public class CheckinClient { .touchScreen(deviceConfiguration.touchScreen) .widthPixels(deviceConfiguration.widthPixels) .build()) - .digest(checkinInfo.digest) + .digest(checkinInfo.getDigest()) .esn(deviceIdent.esn) .fragment(0) .locale(locale.toString()) @@ -154,8 +151,8 @@ public class CheckinClient { builder.macAddress(Arrays.asList(deviceIdent.wifiMac)) .macAddressType(Arrays.asList("wifi")); } - if (checkinInfo.securityToken != 0) { - builder.securityToken(checkinInfo.securityToken) + if (checkinInfo.getSecurityToken() != 0) { + builder.securityToken(checkinInfo.getSecurityToken()) .fragment(1); } return builder.build(); 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 631db813ce4a346f7d2837cc2988ec173448c4a6..95b819849f1b41bf6284673c0368a2fb43bbba56 100644 --- 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 @@ -39,9 +39,9 @@ public class CheckinManager { @SuppressWarnings("MissingPermission") public static synchronized LastCheckinInfo checkin(Context context, boolean force) throws IOException { LastCheckinInfo info = LastCheckinInfo.read(context); - if (!force && info.lastCheckin > System.currentTimeMillis() - MIN_CHECKIN_INTERVAL) + if (!force && info.getLastCheckin() > System.currentTimeMillis() - MIN_CHECKIN_INTERVAL) return null; - if (!CheckinPrefs.get(context).isEnabled()) + if (!CheckinPrefs.isEnabled(context)) return null; List accounts = new ArrayList(); AccountManager accountManager = AccountManager.get(context); @@ -63,13 +63,7 @@ public class CheckinManager { } private static LastCheckinInfo handleResponse(Context context, CheckinResponse response) { - LastCheckinInfo info = new LastCheckinInfo(); - info.androidId = response.androidId; - info.lastCheckin = response.timeMs; - info.securityToken = response.securityToken; - info.digest = response.digest; - info.versionInfo = response.versionInfo; - info.deviceDataVersionInfo = response.deviceDataVersionInfo; + LastCheckinInfo info = new LastCheckinInfo(response); info.write(context); ContentResolver resolver = context.getContentResolver(); diff --git a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinPrefs.java b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinPrefs.java deleted file mode 100644 index ad07305989ff1724a265ccea450253c206b52483..0000000000000000000000000000000000000000 --- a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinPrefs.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020, microG Project Team - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.microg.gms.checkin; - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.util.Log; - -import org.microg.gms.common.PackageUtils; - -import java.io.File; - -public class CheckinPrefs implements SharedPreferences.OnSharedPreferenceChangeListener { - public static final String PREF_ENABLE_CHECKIN = "checkin_enable_service"; - private static CheckinPrefs INSTANCE; - - public static CheckinPrefs get(Context context) { - if (INSTANCE == null) { - PackageUtils.warnIfNotMainProcess(context, CheckinPrefs.class); - if (context == null) return new CheckinPrefs(null); - INSTANCE = new CheckinPrefs(context.getApplicationContext()); - } - return INSTANCE; - } - - private SharedPreferences preferences; - private SharedPreferences systemDefaultPreferences; - private boolean checkinEnabled = false; - - private CheckinPrefs(Context context) { - if (context != null) { - preferences = PreferenceManager.getDefaultSharedPreferences(context); - preferences.registerOnSharedPreferenceChangeListener(this); - try { - systemDefaultPreferences = (SharedPreferences) Context.class.getDeclaredMethod("getSharedPreferences", File.class, int.class).invoke(context, new File("/system/etc/microg.xml"), Context.MODE_PRIVATE); - } catch (Exception ignored) { - } - update(); - } - } - - private boolean getSettingsBoolean(String key, boolean def) { - if (systemDefaultPreferences != null) { - def = systemDefaultPreferences.getBoolean(key, def); - } - return preferences.getBoolean(key, def); - } - - private void update() { - checkinEnabled = getSettingsBoolean(PREF_ENABLE_CHECKIN, false); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - update(); - } - - public boolean isEnabled() { - return checkinEnabled; - } - - public static void setEnabled(Context context, boolean newStatus) { - boolean changed = CheckinPrefs.get(context).isEnabled() != newStatus; - PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(PREF_ENABLE_CHECKIN, newStatus).commit(); - if (!changed) return; - if (newStatus) { - context.sendOrderedBroadcast(new Intent(context, TriggerReceiver.class), null); - } - } -} 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 125d5ebb32d39d9430799d16d1d3ee9042459b16..9db1ca5da303a34207fa304630cc6c377d7d7614 100644 --- 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 @@ -57,7 +57,7 @@ public class CheckinService extends IntentService { private ICheckinService iface = new ICheckinService.Stub() { @Override public String getDeviceDataVersionInfo() throws RemoteException { - return LastCheckinInfo.read(CheckinService.this).deviceDataVersionInfo; + return LastCheckinInfo.read(CheckinService.this).getDeviceDataVersionInfo(); } }; @@ -70,10 +70,10 @@ public class CheckinService extends IntentService { protected void onHandleIntent(Intent intent) { try { ForegroundServiceContext.completeForegroundService(this, intent, TAG); - if (CheckinPrefs.get(this).isEnabled()) { + if (CheckinPrefs.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.androidId)); + Log.d(TAG, "Checked in as " + Long.toHexString(info.getAndroidId())); String accountType = AuthConstants.DEFAULT_ACCOUNT_TYPE; for (Account account : AccountManager.get(this).getAccountsByType(accountType)) { PeopleManager.loadUserInfo(this, account); @@ -86,7 +86,7 @@ public class CheckinService extends IntentService { ResultReceiver receiver = intent.getParcelableExtra(EXTRA_RESULT_RECEIVER); if (receiver != null) { Bundle bundle = new Bundle(); - bundle.putLong(EXTRA_NEW_CHECKIN_TIME, info.lastCheckin); + bundle.putLong(EXTRA_NEW_CHECKIN_TIME, info.getLastCheckin()); receiver.send(Activity.RESULT_OK, bundle); } } @@ -115,6 +115,6 @@ 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); - alarmManager.set(AlarmManager.RTC, Math.max(LastCheckinInfo.read(context).lastCheckin + REGULAR_CHECKIN_INTERVAL, System.currentTimeMillis() + BACKUP_CHECKIN_DELAY), pendingIntent); + 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/LastCheckinInfo.java b/play-services-core/src/main/java/org/microg/gms/checkin/LastCheckinInfo.java deleted file mode 100644 index 30e0a1af98a8092cc43df32e1f35ffd962c8afc9..0000000000000000000000000000000000000000 --- a/play-services-core/src/main/java/org/microg/gms/checkin/LastCheckinInfo.java +++ /dev/null @@ -1,60 +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.checkin; - -import android.content.Context; -import android.content.SharedPreferences; - -public class LastCheckinInfo { - public static final String PREFERENCES_NAME = "checkin"; - public static final String PREF_ANDROID_ID = "androidId"; - public static final String PREF_DIGEST = "digest"; - public static final String PREF_LAST_CHECKIN = "lastCheckin"; - public static final String PREF_SECURITY_TOKEN = "securityToken"; - public static final String PREF_VERSION_INFO = "versionInfo"; - public static final String PREF_DEVICE_DATA_VERSION_INFO = "deviceDataVersionInfo"; - public static final String INITIAL_DIGEST = "1-929a0dca0eee55513280171a8585da7dcd3700f8"; - public long lastCheckin; - public long androidId; - public long securityToken; - public String digest; - public String versionInfo; - public String deviceDataVersionInfo; - - public static LastCheckinInfo read(Context context) { - LastCheckinInfo info = new LastCheckinInfo(); - SharedPreferences preferences = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); - info.androidId = preferences.getLong(PREF_ANDROID_ID, 0); - info.digest = preferences.getString(PREF_DIGEST, INITIAL_DIGEST); - info.lastCheckin = preferences.getLong(PREF_LAST_CHECKIN, 0); - info.securityToken = preferences.getLong(PREF_SECURITY_TOKEN, 0); - info.versionInfo = preferences.getString(PREF_VERSION_INFO, ""); - info.deviceDataVersionInfo = preferences.getString(PREF_DEVICE_DATA_VERSION_INFO, ""); - return info; - } - - public void write(Context context) { - context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE).edit() - .putLong(PREF_ANDROID_ID, androidId) - .putString(PREF_DIGEST, digest) - .putLong(PREF_LAST_CHECKIN, lastCheckin) - .putLong(PREF_SECURITY_TOKEN, securityToken) - .putString(PREF_VERSION_INFO, versionInfo) - .putString(PREF_DEVICE_DATA_VERSION_INFO, deviceDataVersionInfo) - .commit(); - } -} 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 3c8978a2e198d473021b64c1a322b2ffeeef6672..00a27f11aafa2aec5c33dac54f3c42e5a34a1d3b 100644 --- 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 @@ -38,8 +38,8 @@ public class TriggerReceiver extends WakefulBroadcastReceiver { try { boolean force = "android.provider.Telephony.SECRET_CODE".equals(intent.getAction()); - if (CheckinPrefs.get(context).isEnabled() || force) { - if (LastCheckinInfo.read(context).lastCheckin > System.currentTimeMillis() - REGULAR_CHECKIN_INTERVAL && !force) { + if (CheckinPrefs.isEnabled(context) || force) { + if (LastCheckinInfo.read(context).getLastCheckin() > System.currentTimeMillis() - REGULAR_CHECKIN_INTERVAL && !force) { CheckinService.schedule(context); return; } diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/GcmPrefs.java b/play-services-core/src/main/java/org/microg/gms/gcm/GcmPrefs.java deleted file mode 100644 index d37147709684c9661ea7bf88c9233adafa358326..0000000000000000000000000000000000000000 --- a/play-services-core/src/main/java/org/microg/gms/gcm/GcmPrefs.java +++ /dev/null @@ -1,305 +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.gcm; - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.preference.PreferenceManager; -import android.util.Log; - -import org.microg.gms.common.PackageUtils; - -import java.io.File; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListener { - public static final String PREF_FULL_LOG = "gcm_full_log"; - public static final String PREF_LAST_PERSISTENT_ID = "gcm_last_persistent_id"; - public static final String PREF_CONFIRM_NEW_APPS = "gcm_confirm_new_apps"; - public static final String PREF_ENABLE_GCM = "gcm_enable_mcs_service"; - - public static final String PREF_NETWORK_MOBILE = "gcm_network_mobile"; - public static final String PREF_NETWORK_WIFI = "gcm_network_wifi"; - public static final String PREF_NETWORK_ROAMING = "gcm_network_roaming"; - public static final String PREF_NETWORK_OTHER = "gcm_network_other"; - - public static final String PREF_LEARNT_MOBILE = "gcm_learnt_mobile"; - public static final String PREF_LEARNT_WIFI = "gcm_learnt_wifi"; - public static final String PREF_LEARNT_OTHER = "gcm_learnt_other"; - - private static final int MIN_INTERVAL = 5 * 60 * 1000; // 5 minutes - private static final int MAX_INTERVAL = 30 * 60 * 1000; // 30 minutes - - private static GcmPrefs INSTANCE; - - public static GcmPrefs get(Context context) { - if (INSTANCE == null) { - PackageUtils.warnIfNotPersistentProcess(GcmPrefs.class); - INSTANCE = new GcmPrefs(context.getApplicationContext()); - } - return INSTANCE; - } - - private boolean gcmLogEnabled = true; - private String lastPersistedId = ""; - private boolean confirmNewApps = false; - private boolean gcmEnabled = false; - - private int networkMobile = 0; - private int networkWifi = 0; - private int networkRoaming = 0; - private int networkOther = 0; - - private int learntWifi = 300000; - private int learntMobile = 300000; - private int learntOther = 300000; - - private final Context context; - private SharedPreferences preferences; - private SharedPreferences systemDefaultPreferences; - - private GcmPrefs(Context context) { - this.context = context; - preferences = PreferenceManager.getDefaultSharedPreferences(context); - preferences.registerOnSharedPreferenceChangeListener(this); - try { - systemDefaultPreferences = (SharedPreferences) Context.class.getDeclaredMethod("getSharedPreferences", File.class, int.class).invoke(context, new File("/system/etc/microg.xml"), Context.MODE_PRIVATE); - } catch (Exception ignored) { - } - update(); - } - - private boolean getSettingsBoolean(String key, boolean def) { - if (systemDefaultPreferences != null) { - def = systemDefaultPreferences.getBoolean(key, def); - } - return preferences.getBoolean(key, def); - } - - public void update() { - gcmEnabled = getSettingsBoolean(PREF_ENABLE_GCM, false); - gcmLogEnabled = getSettingsBoolean(PREF_FULL_LOG, true); - confirmNewApps = getSettingsBoolean(PREF_CONFIRM_NEW_APPS, false); - - lastPersistedId = preferences.getString(PREF_LAST_PERSISTENT_ID, ""); - - networkMobile = Integer.parseInt(preferences.getString(PREF_NETWORK_MOBILE, "0")); - networkWifi = Integer.parseInt(preferences.getString(PREF_NETWORK_WIFI, "0")); - networkRoaming = Integer.parseInt(preferences.getString(PREF_NETWORK_ROAMING, "0")); - networkOther = Integer.parseInt(preferences.getString(PREF_NETWORK_OTHER, "0")); - - learntMobile = preferences.getInt(PREF_LEARNT_MOBILE, 300000); - learntWifi = preferences.getInt(PREF_LEARNT_WIFI, 300000); - learntOther = preferences.getInt(PREF_LEARNT_OTHER, 300000); - } - - public String getNetworkPrefForInfo(NetworkInfo info) { - if (info == null) return PREF_NETWORK_OTHER; - if (info.isRoaming()) return PREF_NETWORK_ROAMING; - switch (info.getType()) { - case ConnectivityManager.TYPE_MOBILE: - return PREF_NETWORK_MOBILE; - case ConnectivityManager.TYPE_WIFI: - return PREF_NETWORK_WIFI; - default: - return PREF_NETWORK_OTHER; - } - } - - public int getHeartbeatMsFor(NetworkInfo info) { - return getHeartbeatMsFor(getNetworkPrefForInfo(info)); - } - - public int getMobileInterval() { - return networkMobile; - } - - public int getWifiInterval() { - return networkWifi; - } - - public int getRoamingInterval() { - return networkRoaming; - } - - public int getOtherInterval() { - return networkOther; - } - - public void setMobileInterval(int value) { - this.networkMobile = value; - preferences.edit().putString(PREF_NETWORK_MOBILE, Integer.toString(networkMobile)).apply(); - } - - public void setWifiInterval(int value) { - this.networkWifi = value; - preferences.edit().putString(PREF_NETWORK_WIFI, Integer.toString(networkWifi)).apply(); - } - - public void setRoamingInterval(int value) { - this.networkRoaming = value; - preferences.edit().putString(PREF_NETWORK_ROAMING, Integer.toString(networkRoaming)).apply(); - } - - public void setOtherInterval(int value) { - this.networkOther = value; - preferences.edit().putString(PREF_NETWORK_OTHER, Integer.toString(networkOther)).apply(); - } - - public int getHeartbeatMsFor(String pref) { - if (PREF_NETWORK_ROAMING.equals(pref)) { - if (networkRoaming != 0) return networkRoaming * 60000; - else return learntMobile; - } else if (PREF_NETWORK_MOBILE.equals(pref)) { - if (networkMobile != 0) return networkMobile * 60000; - else return learntMobile; - } else if (PREF_NETWORK_WIFI.equals(pref)) { - if (networkWifi != 0) return networkWifi * 60000; - else return learntWifi; - } else { - if (networkOther != 0) return networkOther * 60000; - else return learntOther; - } - } - - public int getNetworkValue(String pref) { - switch (pref) { - case PREF_NETWORK_MOBILE: - return networkMobile; - case PREF_NETWORK_ROAMING: - return networkRoaming; - case PREF_NETWORK_WIFI: - return networkWifi; - default: - return networkOther; - } - } - - public void learnTimeout(String pref) { - Log.d("GmsGcmPrefs", "learnTimeout: " + pref); - switch (pref) { - case PREF_NETWORK_MOBILE: - case PREF_NETWORK_ROAMING: - learntMobile *= 0.95; - break; - case PREF_NETWORK_WIFI: - learntWifi *= 0.95; - break; - default: - learntOther *= 0.95; - break; - } - updateLearntValues(); - } - - public void learnReached(String pref, long time) { - Log.d("GmsGcmPrefs", "learnReached: " + pref + " / " + time); - switch (pref) { - case PREF_NETWORK_MOBILE: - case PREF_NETWORK_ROAMING: - if (time > learntMobile / 4 * 3) - learntMobile *= 1.02; - break; - case PREF_NETWORK_WIFI: - if (time > learntWifi / 4 * 3) - learntWifi *= 1.02; - break; - default: - if (time > learntOther / 4 * 3) - learntOther *= 1.02; - break; - } - updateLearntValues(); - } - - private void updateLearntValues() { - learntMobile = Math.max(MIN_INTERVAL, Math.min(learntMobile, MAX_INTERVAL)); - learntWifi = Math.max(MIN_INTERVAL, Math.min(learntWifi, MAX_INTERVAL)); - learntOther = Math.max(MIN_INTERVAL, Math.min(learntOther, MAX_INTERVAL)); - preferences.edit().putInt(PREF_LEARNT_MOBILE, learntMobile).putInt(PREF_LEARNT_WIFI, learntWifi).putInt(PREF_LEARNT_OTHER, learntOther).apply(); - } - - public int getLearntMobileInterval() { - return learntMobile; - } - - public int getLearntWifiInterval() { - return learntWifi; - } - - public int getLearntOtherInterval() { - return learntOther; - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - update(); - } - - public boolean isEnabled() { - return gcmEnabled; - } - - public void setEnabled(boolean value) { - boolean changed = gcmEnabled != value; - preferences.edit().putBoolean(GcmPrefs.PREF_ENABLE_GCM, value).apply(); - if (!changed) return; - if (!value) { - McsService.stop(context); - } else { - context.sendBroadcast(new Intent(TriggerReceiver.FORCE_TRY_RECONNECT, null, context, TriggerReceiver.class)); - } - } - - public boolean isEnabledFor(NetworkInfo info) { - return isEnabled() && info != null && getHeartbeatMsFor(info) >= 0; - } - - public boolean isGcmLogEnabled() { - return gcmLogEnabled; - } - - public boolean isConfirmNewApps() { - return confirmNewApps; - } - - public void setConfirmNewApps(boolean value) { - confirmNewApps = value; - preferences.edit().putBoolean(PREF_CONFIRM_NEW_APPS, value).apply(); - } - - public List getLastPersistedIds() { - if (lastPersistedId.isEmpty()) return Collections.emptyList(); - return Arrays.asList(lastPersistedId.split("\\|")); - } - - public void extendLastPersistedId(String id) { - if (!lastPersistedId.isEmpty()) lastPersistedId += "|"; - lastPersistedId += id; - preferences.edit().putString(PREF_LAST_PERSISTENT_ID, lastPersistedId).apply(); - } - - public void clearLastPersistedId() { - lastPersistedId = ""; - preferences.edit().putString(PREF_LAST_PERSISTENT_ID, lastPersistedId).apply(); - } -} 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 55ee3b7a8f94f04f5f1c2ba806875381e5c03a01..e5c405a4041a7d121e2280f841d8df2ac29b3ce8 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 @@ -73,6 +73,7 @@ import okio.ByteString; 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.ACTION_C2DM_RECEIVE; import static org.microg.gms.gcm.GcmConstants.EXTRA_APP; import static org.microg.gms.gcm.GcmConstants.EXTRA_APP_OVERRIDE; @@ -234,6 +235,7 @@ public class McsService extends Service implements Handler.Callback { } public synchronized static boolean isConnected(Context context) { + warnIfNotPersistentProcess(McsService.class); if (inputStream == null || !inputStream.isAlive() || outputStream == null || !outputStream.isAlive()) { logd(null, "Connection is not enabled or dead."); return false; @@ -244,13 +246,14 @@ public class McsService extends Service implements Handler.Callback { closeAll(); } else if (SystemClock.elapsedRealtime() - lastHeartbeatAckElapsedRealtime > 2 * heartbeatMs) { logd(null, "No heartbeat for " + (SystemClock.elapsedRealtime() - lastHeartbeatAckElapsedRealtime) / 1000 + " seconds, connection assumed to be dead after " + 2 * heartbeatMs / 1000 + " seconds"); - GcmPrefs.get(context).learnTimeout(activeNetworkPref); + GcmPrefs.get(context).learnTimeout(context, activeNetworkPref); return false; } return true; } public static long getStartTimestamp() { + warnIfNotPersistentProcess(McsService.class); return startTimestamp; } @@ -460,7 +463,7 @@ public class McsService extends Service implements Handler.Callback { private void handleLoginResponse(LoginResponse loginResponse) { if (loginResponse.error == null) { - GcmPrefs.get(this).clearLastPersistedId(); + GcmPrefs.clearLastPersistedId(this); logd(this, "Logged in"); wakeLock.release(); } else { @@ -470,7 +473,7 @@ public class McsService extends Service implements Handler.Callback { private void handleCloudMessage(DataMessageStanza message) { if (message.persistent_id != null) { - GcmPrefs.get(this).extendLastPersistedId(message.persistent_id); + GcmPrefs.get(this).extendLastPersistedId(this, message.persistent_id); } if (SELF_CATEGORY.equals(message.category)) { handleSelfMessage(message); @@ -488,7 +491,7 @@ public class McsService extends Service implements Handler.Callback { } private void handleHeartbeatAck(HeartbeatAck ack) { - GcmPrefs.get(this).learnReached(activeNetworkPref, SystemClock.elapsedRealtime() - lastIncomingNetworkRealtime); + GcmPrefs.get(this).learnReached(this, activeNetworkPref, SystemClock.elapsedRealtime() - lastIncomingNetworkRealtime); lastHeartbeatAckElapsedRealtime = SystemClock.elapsedRealtime(); wakeLock.release(); } @@ -498,13 +501,13 @@ public class McsService extends Service implements Handler.Callback { return new LoginRequest.Builder() .adaptive_heartbeat(false) .auth_service(LoginRequest.AuthService.ANDROID_ID) - .auth_token(Long.toString(info.securityToken)) + .auth_token(Long.toString(info.getSecurityToken())) .id("android-" + SDK_INT) .domain("mcs.android.com") - .device_id("android-" + Long.toHexString(info.androidId)) + .device_id("android-" + Long.toHexString(info.getAndroidId())) .network_type(1) - .resource(Long.toString(info.androidId)) - .user(Long.toString(info.androidId)) + .resource(Long.toString(info.getAndroidId())) + .user(Long.toString(info.getAndroidId())) .use_rmq2(true) .setting(Collections.singletonList(new Setting.Builder().name("new_vc").value("1").build())) .received_persistent_id(GcmPrefs.get(this).getLastPersistedIds()) 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 b3ffca9e645021d061bd6440849650c66a981a96..16220724c677436698e3d8e8e07ef60f23a66c50 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 @@ -87,8 +87,8 @@ public class PushRegisterManager { if (!request.delete) { if (!prefs.isEnabled() || (app != null && !app.allowRegister) || - LastCheckinInfo.read(context).lastCheckin <= 0 || - (app == null && prefs.isConfirmNewApps())) { + LastCheckinInfo.read(context).getLastCheckin() <= 0 || + (app == null && prefs.getConfirmNewApps())) { Bundle bundle = new Bundle(); bundle.putString(EXTRA_ERROR, ERROR_SERVICE_NOT_AVAILABLE); callback.onResult(bundle); 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 e4cfb8510bea101c8557a4afb95ea9b93f9b87f8..43f04028c4d70cca9e0064ddb58ba3e06398bf93 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 @@ -70,8 +70,8 @@ public class RegisterRequest extends HttpFormClient.Request { } public RegisterRequest checkin(LastCheckinInfo lastCheckinInfo) { - androidId = lastCheckinInfo.androidId; - securityToken = lastCheckinInfo.securityToken; + androidId = lastCheckinInfo.getAndroidId(); + securityToken = lastCheckinInfo.getSecurityToken(); return this; } 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 58cbd510ed45ee5ffeea874ba27e6fc4de84fccc..10cc6d682b4d35dde79f93e580dfda50288cb2ad 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 @@ -65,7 +65,7 @@ public class TriggerReceiver extends WakefulBroadcastReceiver { McsService.resetCurrentDelay(); } - if (LastCheckinInfo.read(context).androidId == 0) { + if (LastCheckinInfo.read(context).getAndroidId() == 0) { Log.d(TAG, "Ignoring " + intent + ": need to checkin first."); return; } diff --git a/play-services-core/src/main/java/org/microg/gms/tapandpay/TapAndPayImpl.java b/play-services-core/src/main/java/org/microg/gms/tapandpay/TapAndPayImpl.java deleted file mode 100644 index 406326503ff769707c32611c96b4234dcc94164a..0000000000000000000000000000000000000000 --- a/play-services-core/src/main/java/org/microg/gms/tapandpay/TapAndPayImpl.java +++ /dev/null @@ -1,33 +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 org.microg.gms.tapandpay; - -import com.google.android.gms.tapandpay.internal.ITapAndPayService; -import android.os.Parcel; -import android.os.RemoteException; -import android.util.Log; - -public class TapAndPayImpl extends ITapAndPayService.Stub { - private static final String TAG = "GmsTapAndPayImpl"; - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { - if (super.onTransact(code, data, reply, flags)) return true; - Log.d(TAG, "onTransact [unknown]: " + code + ", " + data + ", " + flags); - return false; - } -} diff --git a/play-services-core/src/main/java/org/microg/gms/tapandpay/TapAndPayService.java b/play-services-core/src/main/java/org/microg/gms/tapandpay/TapAndPayService.java deleted file mode 100644 index 082234e643bdc741cfa87af6e17efced1838b244..0000000000000000000000000000000000000000 --- a/play-services-core/src/main/java/org/microg/gms/tapandpay/TapAndPayService.java +++ /dev/null @@ -1,38 +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 org.microg.gms.tapandpay; - -import android.os.RemoteException; - -import com.google.android.gms.common.api.CommonStatusCodes; -import com.google.android.gms.common.internal.GetServiceRequest; -import com.google.android.gms.common.internal.IGmsCallbacks; - -import org.microg.gms.BaseService; -import org.microg.gms.common.GmsService; - -public class TapAndPayService extends BaseService { - public TapAndPayService() { - super("GmsTapAndPaySvc", GmsService.TAP_AND_PAY); - } - - @Override - public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException { - callback.onPostInitComplete(CommonStatusCodes.SUCCESS, new TapAndPayImpl(), null); - - } -} diff --git a/play-services-core/src/main/java/org/microg/gms/wearable/MessageHandler.java b/play-services-core/src/main/java/org/microg/gms/wearable/MessageHandler.java index b648b3aea4bb8fac9699fea7de208c81b90126d8..6a84253ca9f73df7e6edfbd987e786adf08e4b86 100644 --- a/play-services-core/src/main/java/org/microg/gms/wearable/MessageHandler.java +++ b/play-services-core/src/main/java/org/microg/gms/wearable/MessageHandler.java @@ -48,7 +48,7 @@ public class MessageHandler extends ServerMessageListener { private String peerNodeId; public MessageHandler(WearableImpl wearable, ConnectionConfiguration config) { - this(wearable, config, new Build().model, config.nodeId, LastCheckinInfo.read(wearable.getContext()).androidId); + this(wearable, config, new Build().model, config.nodeId, LastCheckinInfo.read(wearable.getContext()).getAndroidId()); } private MessageHandler(WearableImpl wearable, ConnectionConfiguration config, String name, String networkId, long androidId) { 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 new file mode 100644 index 0000000000000000000000000000000000000000..f5797f5671dd819b7ecf1ad1588a3976753dcce0 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/AuthPrefs.kt @@ -0,0 +1,23 @@ +package org.microg.gms.auth + +import android.content.Context +import org.microg.gms.settings.SettingsContract +import org.microg.gms.settings.SettingsContract.Auth + +object AuthPrefs { + + @JvmStatic + fun isTrustGooglePermitted(context: Context): Boolean { + return SettingsContract.getSettings(context, Auth.CONTENT_URI, arrayOf(Auth.TRUST_GOOGLE)) { c -> + c.getInt(0) != 0 + } + } + + @JvmStatic + fun isAuthVisible(context: Context): Boolean { + return SettingsContract.getSettings(context, Auth.CONTENT_URI, arrayOf(Auth.VISIBLE)) { c -> + c.getInt(0) != 0 + } + } + +} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/CredentialPickerActivity.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialPickerActivity.kt similarity index 98% rename from play-services-core/src/main/kotlin/org/microg/gms/ui/CredentialPickerActivity.kt rename to play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialPickerActivity.kt index c5f3849c088e6d963566a458fa770798927746f7..e8e3fac3b3cb4e0229c30516613ea763811ea65c 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/CredentialPickerActivity.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialPickerActivity.kt @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package org.microg.gms.ui +package org.microg.gms.auth import android.app.Activity import android.os.Bundle diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialsService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialsService.kt new file mode 100644 index 0000000000000000000000000000000000000000..6f571df3a2a1fc9d939f61966d395da95e18373c --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialsService.kt @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.auth + +import android.os.Bundle +import android.util.Log +import com.google.android.gms.auth.api.credentials.CredentialRequest +import com.google.android.gms.auth.api.credentials.internal.* +import com.google.android.gms.common.api.CommonStatusCodes +import com.google.android.gms.common.api.Status +import com.google.android.gms.common.internal.GetServiceRequest +import com.google.android.gms.common.internal.IGmsCallbacks +import org.microg.gms.BaseService +import org.microg.gms.common.GmsService + +const val TAG = "GmsCredentials" + +class CredentialsService : BaseService(TAG, GmsService.CREDENTIALS) { + override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) { + callback.onPostInitComplete(CommonStatusCodes.SUCCESS, CredentialsServiceImpl(), Bundle()) + } +} + +class CredentialsServiceImpl : ICredentialsService.Stub() { + override fun request(callbacks: ICredentialsCallbacks, request: CredentialRequest) { + Log.d(TAG, "request($request)") + callbacks.onStatus(Status.CANCELED) + } + + override fun save(callbacks: ICredentialsCallbacks, request: SaveRequest) { + Log.d(TAG, "save($request)") + callbacks.onStatus(Status.CANCELED) + } + + override fun delete(callbacks: ICredentialsCallbacks, request: DeleteRequest) { + Log.d(TAG, "delete($request)") + callbacks.onStatus(Status.CANCELED) + } + + override fun disableAutoSignIn(callbacks: ICredentialsCallbacks) { + Log.d(TAG, "disableAutoSignIn()") + callbacks.onStatus(Status.SUCCESS) + } + + override fun generatePassword(callbacks: ICredentialsCallbacks, request: GeneratePasswordRequest) { + Log.d(TAG, "generatePassword($request)") + callbacks.onStatus(Status.SUCCESS) + } + +} 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/CheckinPrefs.kt new file mode 100644 index 0000000000000000000000000000000000000000..bd122c35a105817298606e71dca3dfb57733efc6 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/checkin/CheckinPrefs.kt @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ +package org.microg.gms.checkin + +import android.content.Context +import org.microg.gms.settings.SettingsContract +import org.microg.gms.settings.SettingsContract.CheckIn + +object CheckinPrefs { + + @JvmStatic + fun isEnabled(context: Context): Boolean { + val projection = arrayOf(CheckIn.ENABLED) + return SettingsContract.getSettings(context, CheckIn.CONTENT_URI, projection) { c -> + c.getInt(0) != 0 + } + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..ccdb31af39f8a6af5711714e2b3202b79bdb3927 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/checkin/LastCheckinInfo.kt @@ -0,0 +1,82 @@ +/* + * 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.checkin + +import android.content.Context +import org.microg.gms.settings.SettingsContract +import org.microg.gms.settings.SettingsContract.CheckIn + +data class LastCheckinInfo( + val lastCheckin: Long, + val androidId: Long, + val securityToken: Long, + val digest: String, + val versionInfo: String, + val deviceDataVersionInfo: String, +) { + + constructor(r: CheckinResponse) : this( + lastCheckin = r.timeMs ?: 0L, + androidId = r.androidId ?: 0L, + securityToken = r.securityToken ?: 0L, + digest = r.digest ?: CheckIn.INITIAL_DIGEST, + versionInfo = r.versionInfo ?: "", + deviceDataVersionInfo = r.deviceDataVersionInfo ?: "", + ) + + companion object { + @JvmStatic + fun read(context: Context): LastCheckinInfo { + val projection = arrayOf( + CheckIn.ANDROID_ID, + CheckIn.DIGEST, + CheckIn.LAST_CHECK_IN, + CheckIn.SECURITY_TOKEN, + CheckIn.VERSION_INFO, + CheckIn.DEVICE_DATA_VERSION_INFO, + ) + return SettingsContract.getSettings(context, CheckIn.CONTENT_URI, projection) { c -> + LastCheckinInfo( + androidId = c.getLong(0), + digest = c.getString(1), + lastCheckin = c.getLong(2), + securityToken = c.getLong(3), + versionInfo = c.getString(4), + deviceDataVersionInfo = c.getString(5), + ) + } + } + + @JvmStatic + fun clear(context: Context) = SettingsContract.setSettings(context, CheckIn.CONTENT_URI) { + put(CheckIn.ANDROID_ID, 0L) + put(CheckIn.DIGEST, CheckIn.INITIAL_DIGEST) + put(CheckIn.LAST_CHECK_IN, 0L) + put(CheckIn.SECURITY_TOKEN, 0L) + put(CheckIn.VERSION_INFO, "") + put(CheckIn.DEVICE_DATA_VERSION_INFO, "") + } + } + + fun write(context: Context) = SettingsContract.setSettings(context, CheckIn.CONTENT_URI) { + put(CheckIn.ANDROID_ID, androidId) + put(CheckIn.DIGEST, digest) + put(CheckIn.LAST_CHECK_IN, lastCheckin) + put(CheckIn.SECURITY_TOKEN, securityToken) + put(CheckIn.VERSION_INFO, versionInfo) + put(CheckIn.DEVICE_DATA_VERSION_INFO, deviceDataVersionInfo) + } +} 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 d8902b8fdd3f8c6c111bf18c1b41fd1e3fc727cc..e61eb4d153f9efa1b4aba052920b01c1cfeb201a 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 @@ -5,89 +5,38 @@ package org.microg.gms.checkin -import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import android.content.IntentFilter -import android.util.Log +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +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 -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine - -private const val ACTION_SERVICE_INFO_REQUEST = "org.microg.gms.checkin.SERVICE_INFO_REQUEST" -private const val ACTION_UPDATE_CONFIGURATION = "org.microg.gms.checkin.UPDATE_CONFIGURATION" -private const val ACTION_SERVICE_INFO_RESPONSE = "org.microg.gms.checkin.SERVICE_INFO_RESPONSE" -private const val EXTRA_SERVICE_INFO = "org.microg.gms.checkin.SERVICE_INFO" -private const val EXTRA_CONFIGURATION = "org.microg.gms.checkin.CONFIGURATION" -private const val TAG = "GmsCheckinStatusInfo" data class ServiceInfo(val configuration: ServiceConfiguration, val lastCheckin: Long, val androidId: Long) : Serializable -data class ServiceConfiguration(val enabled: Boolean) : Serializable { - fun saveToPrefs(context: Context) { - CheckinPrefs.setEnabled(context, enabled) - } -} - -private fun CheckinPrefs.toConfiguration(): ServiceConfiguration = ServiceConfiguration(isEnabled) - -class ServiceInfoReceiver : BroadcastReceiver() { - private fun sendInfoResponse(context: Context) { - context.sendOrderedBroadcast(Intent(ACTION_SERVICE_INFO_RESPONSE).apply { - setPackage(context.packageName) - val checkinInfo = LastCheckinInfo.read(context) - putExtra(EXTRA_SERVICE_INFO, ServiceInfo(CheckinPrefs.get(context).toConfiguration(), checkinInfo.lastCheckin, checkinInfo.androidId)) - }, null) - } +data class ServiceConfiguration(val enabled: Boolean) : Serializable - override fun onReceive(context: Context, intent: Intent) { - try { - when (intent.action) { - ACTION_UPDATE_CONFIGURATION -> { - (intent.getSerializableExtra(EXTRA_CONFIGURATION) as? ServiceConfiguration)?.saveToPrefs(context) - } - } - sendInfoResponse(context) - } catch (e: Exception) { - Log.w(TAG, e) - } +suspend fun getCheckinServiceInfo(context: Context): ServiceInfo = withContext(Dispatchers.IO) { + val projection = arrayOf(CheckIn.ENABLED, CheckIn.LAST_CHECK_IN, CheckIn.ANDROID_ID) + getSettings(context, CheckIn.CONTENT_URI, projection) { c -> + ServiceInfo( + configuration = ServiceConfiguration(c.getInt(0) != 0), + lastCheckin = c.getLong(1), + androidId = c.getLong(2), + ) } } - - -private suspend fun sendToServiceInfoReceiver(intent: Intent, context: Context): ServiceInfo = suspendCoroutine { - context.registerReceiver(object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - context.unregisterReceiver(this) - val serviceInfo = try { - intent.getSerializableExtra(EXTRA_SERVICE_INFO) as ServiceInfo - } catch (e: Exception) { - it.resumeWithException(e) - return - } - try { - it.resume(serviceInfo) - } catch (e: Exception) { - Log.w(TAG, e) - } - } - }, IntentFilter(ACTION_SERVICE_INFO_RESPONSE)) - try { - context.sendOrderedBroadcast(intent, null) - } catch (e: Exception) { - it.resumeWithException(e) +suspend fun setCheckinServiceConfiguration(context: Context, configuration: ServiceConfiguration) = withContext(Dispatchers.IO) { + val serviceInfo = getCheckinServiceInfo(context) + if (serviceInfo.configuration == configuration) return@withContext + // enabled state is not already set, setting it now + setSettings(context, CheckIn.CONTENT_URI) { + put(CheckIn.ENABLED, configuration.enabled) + } + if (configuration.enabled) { + context.sendOrderedBroadcast(Intent(context, TriggerReceiver::class.java), null) } } - -suspend fun getCheckinServiceInfo(context: Context): ServiceInfo = sendToServiceInfoReceiver( - Intent(context, ServiceInfoReceiver::class.java).apply { - action = ACTION_SERVICE_INFO_REQUEST - }, context) - -suspend fun setCheckinServiceConfiguration(context: Context, configuration: ServiceConfiguration): ServiceInfo = sendToServiceInfoReceiver( - Intent(context, ServiceInfoReceiver::class.java).apply { - action = ACTION_UPDATE_CONFIGURATION - putExtra(EXTRA_CONFIGURATION, configuration) - }, context) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/fonts/FontsProvider.kt b/play-services-core/src/main/kotlin/org/microg/gms/fonts/FontsProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..a15180c5a433e3d5cf005436f4aee271d3149d60 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/fonts/FontsProvider.kt @@ -0,0 +1,97 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.fonts + +import android.content.ContentProvider +import android.content.ContentValues +import android.database.Cursor +import android.database.MatrixCursor +import android.net.Uri +import android.os.Bundle +import android.os.ParcelFileDescriptor +import android.os.ParcelFileDescriptor.MODE_READ_ONLY +import android.util.Log +import java.io.File + +class FontsProvider : ContentProvider() { + + override fun onCreate(): Boolean { + Log.d(TAG, "onCreate") + return true + } + + override fun call(method: String, arg: String?, extras: Bundle?): Bundle? { + Log.d(TAG, "call $method $arg $extras") + return null + } + + override fun query( + uri: Uri, + projection: Array?, + selection: String?, + selectionArgs: Array?, + sortOrder: String? + ): Cursor { + Log.e(TAG, "query: $uri ${projection?.toList()} $selection") + val cursor = MatrixCursor(COLUMNS) + // We could also return an empty cursor here, but some apps have been reported to crash + // when their expected font is not returned by Google's font provider. + cursor.addRow( + arrayOf( + 1337L, // file_id + 0, // font_ttc_index + null, // font_variation_settings + 400, // font_weight + 0, // font_italic + 0, // result_code: RESULT_CODE_OK + ) + ) + return cursor + } + + override fun insert(uri: Uri, values: ContentValues?): Uri { + Log.d(TAG, "insert: $uri, $values") + return uri + } + + override fun update( + uri: Uri, + values: ContentValues?, + selection: String?, + selectionArgs: Array? + ): Int { + Log.d(TAG, "update: $uri, $values, $selection, $selectionArgs") + return 0 + } + + override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int { + Log.d(TAG, "delete: $uri, $selection, $selectionArgs") + return 0 + } + + override fun getType(uri: Uri): String { + Log.d(TAG, "getType: $uri") + return "font/ttf" + } + + override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? { + Log.d(TAG, "openFile: $uri mode: $mode") + val file = File("/system/fonts/Roboto-Regular.ttf") + return ParcelFileDescriptor.open(file, MODE_READ_ONLY) + } + + companion object { + private const val TAG = "FontsProvider" + private val COLUMNS = arrayOf( + "file_id", + "font_ttc_index", + "font_variation_settings", + "font_weight", + "font_italic", + "result_code" + ) + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..1f1e75d454da4de67dbe98ad0e49939f8ff7da6c --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/gcm/GcmPrefs.kt @@ -0,0 +1,181 @@ +package org.microg.gms.gcm + +import android.content.Context +import android.content.Intent +import android.net.ConnectivityManager +import android.net.NetworkInfo +import android.util.Log +import org.microg.gms.gcm.TriggerReceiver.FORCE_TRY_RECONNECT +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, + val lastPersistedId: String?, + val confirmNewApps: Boolean, + val gcmEnabled: Boolean, + val networkMobile: Int, + val networkWifi: Int, + val networkRoaming: Int, + val networkOther: Int, + val learntMobileInterval: Int, + val learntWifiInterval: Int, + val learntOtherInterval: Int, +) { + + val isEnabled: Boolean get() = gcmEnabled + + val lastPersistedIds: List + get() = if (lastPersistedId.isNullOrEmpty()) emptyList() else lastPersistedId.split("\\|") + + companion object { + const val PREF_CONFIRM_NEW_APPS = Gcm.CONFIRM_NEW_APPS + const val PREF_NETWORK_MOBILE = Gcm.NETWORK_MOBILE + const val PREF_NETWORK_WIFI = Gcm.NETWORK_WIFI + 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 = 30 * 60 * 1000 // 30 minutes + + @JvmStatic + fun get(context: Context): GcmPrefs { + return SettingsContract.getSettings(context, Gcm.CONTENT_URI, Gcm.PROJECTION) { c -> + GcmPrefs( + isGcmLogEnabled = c.getInt(0) != 0, + lastPersistedId = c.getString(1), + confirmNewApps = c.getInt(2) != 0, + gcmEnabled = c.getInt(3) != 0, + networkMobile = c.getInt(4), + networkWifi = c.getInt(5), + networkRoaming = c.getInt(6), + networkOther = c.getInt(7), + learntMobileInterval = c.getInt(8), + learntWifiInterval = c.getInt(9), + learntOtherInterval = c.getInt(10), + ) + } + } + + fun write(context: Context, config: ServiceConfiguration) { + val gcmPrefs = get(context) + setSettings(context, Gcm.CONTENT_URI) { + put(Gcm.ENABLE_GCM, config.enabled) + put(Gcm.CONFIRM_NEW_APPS, config.confirmNewApps) + put(Gcm.NETWORK_MOBILE, config.mobile) + put(Gcm.NETWORK_WIFI, config.wifi) + put(Gcm.NETWORK_ROAMING, config.roaming) + put(Gcm.NETWORK_OTHER, config.other) + } + gcmPrefs.setEnabled(context, config.enabled) + } + + @JvmStatic + fun clearLastPersistedId(context: Context) { + setSettings(context, Gcm.CONTENT_URI) { + put(Gcm.LAST_PERSISTENT_ID, "") + } + } + } + + /** + * Call this whenever the enabled state of GCM has changed. + */ + private fun setEnabled(context: Context, enabled: Boolean) { + if (gcmEnabled == enabled) return + if (enabled) { + val i = Intent(FORCE_TRY_RECONNECT, null, context, TriggerReceiver::class.java) + context.sendBroadcast(i) + } else { + McsService.stop(context) + } + } + + @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) { + ConnectivityManager.TYPE_MOBILE -> PREF_NETWORK_MOBILE + ConnectivityManager.TYPE_WIFI -> PREF_NETWORK_WIFI + else -> PREF_NETWORK_OTHER + } + } + + @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 * 60000 else learntMobileInterval + } else if (PREF_NETWORK_MOBILE == pref) { + if (networkMobile != 0) networkMobile * 60000 else learntMobileInterval + } else if (PREF_NETWORK_WIFI == pref) { + if (networkWifi != 0) networkWifi * 60000 else learntWifiInterval + } else { + if (networkOther != 0) networkOther * 60000 else learntOtherInterval + } + } + + fun learnTimeout(context: Context, pref: String) { + Log.d("GmsGcmPrefs", "learnTimeout: $pref") + when (pref) { + PREF_NETWORK_MOBILE, PREF_NETWORK_ROAMING -> setSettings(context, Gcm.CONTENT_URI) { + put(Gcm.LEARNT_MOBILE, (learntMobileInterval * 0.95).toInt()) + } + PREF_NETWORK_WIFI -> setSettings(context, Gcm.CONTENT_URI) { + put(Gcm.LEARNT_WIFI, (learntWifiInterval * 0.95).toInt()) + } + else -> setSettings(context, Gcm.CONTENT_URI) { + put(Gcm.LEARNT_OTHER, (learntOtherInterval * 0.95).toInt()) + } + } + } + + fun learnReached(context: Context, pref: String, time: Long) { + Log.d("GmsGcmPrefs", "learnReached: $pref / $time") + when (pref) { + PREF_NETWORK_MOBILE, PREF_NETWORK_ROAMING -> { + if (time > learntMobileInterval / 4 * 3) { + val newInterval = (learntMobileInterval * 1.02).toInt() + setSettings(context, Gcm.CONTENT_URI) { + 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.CONTENT_URI) { + 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.CONTENT_URI) { + 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 + } + + fun extendLastPersistedId(context: Context, id: String) { + val newId = if (lastPersistedId.isNullOrEmpty()) id else "$lastPersistedId|$id" + setSettings(context, Gcm.CONTENT_URI) { + 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 02fe6f0a2642a2d0640216d5620e2621a0efc96f..3f2284766088d7059a1859c46a526f69d0079231 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 @@ -30,7 +30,7 @@ import kotlin.coroutines.suspendCoroutine private const val TAG = "GmsGcmRegister" private suspend fun ensureCheckinIsUpToDate(context: Context) { - if (!CheckinPrefs.get(context).isEnabled) throw RuntimeException("Checkin disabled") + if (!CheckinPrefs.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 -> @@ -55,7 +55,7 @@ private suspend fun ensureCheckinIsUpToDate(context: Context) { private suspend fun ensureAppRegistrationAllowed(context: Context, database: GcmDatabase, packageName: String) { if (!GcmPrefs.get(context).isEnabled) throw RuntimeException("GCM disabled") val app = database.getApp(packageName) - if (app == null && GcmPrefs.get(context).isConfirmNewApps) { + if (app == null && GcmPrefs.get(context).confirmNewApps) { val accepted: Boolean = suspendCoroutine { continuation -> val i = Intent(context, AskPushPermission::class.java) i.putExtra(AskPushPermission.EXTRA_REQUESTED_PACKAGE, packageName) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/gcm/ServiceInfo.kt b/play-services-core/src/main/kotlin/org/microg/gms/gcm/ServiceInfo.kt index cc400f22be83aaa2687b5ba35b6e905ea3446458..5d6a039276840f9a589a447596ecb1c0223532d0 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/gcm/ServiceInfo.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/gcm/ServiceInfo.kt @@ -10,52 +10,40 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.util.Log +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import java.io.Serializable import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine private const val ACTION_SERVICE_INFO_REQUEST = "org.microg.gms.gcm.SERVICE_INFO_REQUEST" -private const val ACTION_UPDATE_CONFIGURATION = "org.microg.gms.gcm.UPDATE_CONFIGURATION" private const val ACTION_SERVICE_INFO_RESPONSE = "org.microg.gms.gcm.SERVICE_INFO_RESPONSE" private const val EXTRA_SERVICE_INFO = "org.microg.gms.gcm.SERVICE_INFO" -private const val EXTRA_CONFIGURATION = "org.microg.gms.gcm.CONFIGURATION" private const val TAG = "GmsGcmStatusInfo" data class ServiceInfo(val configuration: ServiceConfiguration, val connected: Boolean, val startTimestamp: Long, val learntMobileInterval: Int, val learntWifiInterval: Int, val learntOtherInterval: Int) : Serializable -data class ServiceConfiguration(val enabled: Boolean, val confirmNewApps: Boolean, val mobile: Int, val wifi: Int, val roaming: Int, val other: Int) : Serializable { - fun saveToPrefs(context: Context) { - GcmPrefs.get(context).apply { - isEnabled = enabled - isConfirmNewApps = confirmNewApps - mobileInterval = mobile - wifiInterval = wifi - roamingInterval = roaming - otherInterval = other - } - } -} +data class ServiceConfiguration(val enabled: Boolean, val confirmNewApps: Boolean, val mobile: Int, val wifi: Int, val roaming: Int, val other: Int) : Serializable -private fun GcmPrefs.toConfiguration(): ServiceConfiguration = ServiceConfiguration(isEnabled, isConfirmNewApps, mobileInterval, wifiInterval, roamingInterval, otherInterval) +private fun GcmPrefs.toConfiguration(): ServiceConfiguration = ServiceConfiguration(isEnabled, confirmNewApps, networkMobile, networkWifi, networkRoaming, networkOther) class ServiceInfoReceiver : BroadcastReceiver() { - private fun sendInfoResponse(context: Context) { - context.sendOrderedBroadcast(Intent(ACTION_SERVICE_INFO_RESPONSE).apply { - setPackage(context.packageName) - val prefs = GcmPrefs.get(context) - putExtra(EXTRA_SERVICE_INFO, ServiceInfo(prefs.toConfiguration(), McsService.isConnected(context), McsService.getStartTimestamp(), prefs.learntMobileInterval, prefs.learntWifiInterval, prefs.learntOtherInterval)) - }, null) - } - override fun onReceive(context: Context, intent: Intent) { try { - when (intent.action) { - ACTION_UPDATE_CONFIGURATION -> { - (intent.getSerializableExtra(EXTRA_CONFIGURATION) as? ServiceConfiguration)?.saveToPrefs(context) - } - } - sendInfoResponse(context) + context.sendOrderedBroadcast(Intent(ACTION_SERVICE_INFO_RESPONSE).apply { + setPackage(context.packageName) + val prefs = GcmPrefs.get(context) + val info = ServiceInfo( + configuration = prefs.toConfiguration(), + connected = McsService.isConnected(context), + startTimestamp = McsService.getStartTimestamp(), + learntMobileInterval = prefs.learntMobileInterval, + learntWifiInterval = prefs.learntWifiInterval, + learntOtherInterval = prefs.learntOtherInterval + ) + putExtra(EXTRA_SERVICE_INFO, info) + }, null) } catch (e: Exception) { Log.w(TAG, e) } @@ -87,12 +75,11 @@ private suspend fun sendToServiceInfoReceiver(intent: Intent, context: Context): } suspend fun getGcmServiceInfo(context: Context): ServiceInfo = sendToServiceInfoReceiver( + // this is still using a broadcast, because it calls into McsService in the persistent process Intent(context, ServiceInfoReceiver::class.java).apply { action = ACTION_SERVICE_INFO_REQUEST }, context) -suspend fun setGcmServiceConfiguration(context: Context, configuration: ServiceConfiguration): ServiceInfo = sendToServiceInfoReceiver( - Intent(context, ServiceInfoReceiver::class.java).apply { - action = ACTION_UPDATE_CONFIGURATION - putExtra(EXTRA_CONFIGURATION, configuration) - }, context) +suspend fun setGcmServiceConfiguration(context: Context, configuration: ServiceConfiguration) = withContext(Dispatchers.IO) { + GcmPrefs.write(context, configuration) +} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt b/play-services-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..f635539c1423fd123fcb3859ea8aac7510e3516c --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt @@ -0,0 +1,256 @@ +package org.microg.gms.settings + +import android.content.ContentProvider +import android.content.ContentValues +import android.content.Context +import android.content.Context.MODE_PRIVATE +import android.content.SharedPreferences +import android.database.Cursor +import android.database.MatrixCursor +import android.net.Uri +import android.util.Log +import androidx.preference.PreferenceManager +import org.microg.gms.common.PackageUtils.warnIfNotMainProcess +import org.microg.gms.settings.SettingsContract.AUTHORITY +import org.microg.gms.settings.SettingsContract.Auth +import org.microg.gms.settings.SettingsContract.CheckIn +import org.microg.gms.settings.SettingsContract.Exposure +import org.microg.gms.settings.SettingsContract.Gcm +import java.io.File + +/** + * All settings access should go through this [ContentProvider], + * because it provides safe access from different processes which normal [SharedPreferences] don't. + */ +class SettingsProvider : ContentProvider() { + + private val preferences: SharedPreferences by lazy { + PreferenceManager.getDefaultSharedPreferences(context) + } + private val checkInPrefs by lazy { + context!!.getSharedPreferences(CheckIn.PREFERENCES_NAME, MODE_PRIVATE) + } + private val systemDefaultPreferences: SharedPreferences? by lazy { + try { + Context::class.java.getDeclaredMethod( + "getSharedPreferences", + File::class.java, + Int::class.javaPrimitiveType + ).invoke(context, File("/system/etc/microg.xml"), MODE_PRIVATE) as SharedPreferences + } catch (ignored: Exception) { + null + } + } + + override fun onCreate(): Boolean { + return true + } + + override fun query( + uri: Uri, + projection: Array?, + selection: String?, + selectionArgs: Array?, + sortOrder: String? + ): Cursor? = when (uri) { + CheckIn.CONTENT_URI -> queryCheckIn(projection ?: CheckIn.PROJECTION) + Gcm.CONTENT_URI -> queryGcm(projection ?: Gcm.PROJECTION) + Auth.CONTENT_URI -> queryAuth(projection ?: Auth.PROJECTION) + Exposure.CONTENT_URI -> queryExposure(projection ?: Exposure.PROJECTION) + else -> null + } + + override fun update( + uri: Uri, + values: ContentValues?, + selection: String?, + selectionArgs: Array? + ): Int { + warnIfNotMainProcess(context, this.javaClass) + if (values == null) return 0 + when (uri) { + CheckIn.CONTENT_URI -> updateCheckIn(values) + Gcm.CONTENT_URI -> updateGcm(values) + Auth.CONTENT_URI -> updateAuth(values) + Exposure.CONTENT_URI -> updateExposure(values) + else -> return 0 + } + return 1 + } + + private fun queryCheckIn(p: Array): Cursor = MatrixCursor(p).addRow(p) { key -> + when (key) { + CheckIn.ENABLED -> getSettingsBoolean(key, true) + CheckIn.ANDROID_ID -> checkInPrefs.getLong(key, 0) + CheckIn.DIGEST -> checkInPrefs.getString(key, CheckIn.INITIAL_DIGEST) + ?: CheckIn.INITIAL_DIGEST + CheckIn.LAST_CHECK_IN -> checkInPrefs.getLong(key, 0) + CheckIn.SECURITY_TOKEN -> checkInPrefs.getLong(key, 0) + CheckIn.VERSION_INFO -> checkInPrefs.getString(key, "") ?: "" + CheckIn.DEVICE_DATA_VERSION_INFO -> checkInPrefs.getString(key, "") ?: "" + else -> throw IllegalArgumentException() + } + } + + private fun updateCheckIn(values: ContentValues) { + if (values.size() == 0) return + if (values.size() == 1 && values.containsKey(CheckIn.ENABLED)) { + // special case: only changing enabled state + updateCheckInEnabled(values.getAsBoolean(CheckIn.ENABLED)) + return + } + val editor = checkInPrefs.edit() + values.valueSet().forEach { (key, value) -> + // TODO remove log + Log.e("TEST", "check-in update: $key = $value") + if (key == CheckIn.ENABLED) { + // special case: not saved in checkInPrefs + updateCheckInEnabled(value as Boolean) + } + when (key) { + CheckIn.ANDROID_ID -> editor.putLong(key, value as Long) + CheckIn.DIGEST -> editor.putString(key, value as String?) + CheckIn.LAST_CHECK_IN -> editor.putLong(key, value as Long) + CheckIn.SECURITY_TOKEN -> editor.putLong(key, value as Long) + CheckIn.VERSION_INFO -> editor.putString(key, value as String?) + CheckIn.DEVICE_DATA_VERSION_INFO -> editor.putString(key, value as String?) + } + } + editor.apply() + } + + private fun updateCheckInEnabled(enabled: Boolean) { + preferences.edit() + .putBoolean(CheckIn.ENABLED, enabled) + .apply() + } + + private fun queryGcm(p: Array): Cursor = MatrixCursor(p).addRow(p) { key -> + when (key) { + Gcm.ENABLE_GCM -> getSettingsBoolean(key, false) + Gcm.FULL_LOG -> getSettingsBoolean(key, true) + Gcm.CONFIRM_NEW_APPS -> getSettingsBoolean(key, false) + + Gcm.LAST_PERSISTENT_ID -> preferences.getString(key, "") ?: "" + + Gcm.NETWORK_MOBILE -> Integer.parseInt(preferences.getString(key, "0") ?: "0") + Gcm.NETWORK_WIFI -> Integer.parseInt(preferences.getString(key, "0") ?: "0") + 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, 300000) + Gcm.LEARNT_WIFI -> preferences.getInt(key, 300000) + Gcm.LEARNT_OTHER -> preferences.getInt(key, 300000) + + else -> throw IllegalArgumentException("Unknown key: $key") + } + } + + private fun updateGcm(values: ContentValues) { + if (values.size() == 0) return + val editor = preferences.edit() + values.valueSet().forEach { (key, value) -> + // TODO remove log + Log.e("TEST", "gcm update: $key = $value") + when (key) { + Gcm.ENABLE_GCM -> editor.putBoolean(key, value as Boolean) + Gcm.FULL_LOG -> editor.putBoolean(key, value as Boolean) + Gcm.CONFIRM_NEW_APPS -> editor.putBoolean(key, value as Boolean) + + Gcm.LAST_PERSISTENT_ID -> editor.putString(key, value as String?) + + Gcm.NETWORK_MOBILE -> editor.putString(key, (value as Int).toString()) + Gcm.NETWORK_WIFI -> editor.putString(key, (value as Int).toString()) + Gcm.NETWORK_ROAMING -> editor.putString(key, (value as Int).toString()) + Gcm.NETWORK_OTHER -> editor.putString(key, (value as Int).toString()) + + Gcm.LEARNT_MOBILE -> editor.putInt(key, value as Int) + Gcm.LEARNT_WIFI -> editor.putInt(key, value as Int) + Gcm.LEARNT_OTHER -> editor.putInt(key, value as Int) + + else -> throw IllegalArgumentException("Unknown key: $key") + } + } + editor.apply() + } + + private fun queryAuth(p: Array): Cursor = MatrixCursor(p).addRow(p) { key -> + when (key) { + Auth.TRUST_GOOGLE -> getSettingsBoolean(key, true) + Auth.VISIBLE -> getSettingsBoolean(key, false) + else -> throw IllegalArgumentException("Unknown key: $key") + } + } + + private fun updateAuth(values: ContentValues) { + if (values.size() == 0) return + val editor = preferences.edit() + values.valueSet().forEach { (key, value) -> + // TODO remove log + Log.e("TEST", "auth update: $key = $value") + when (key) { + Auth.TRUST_GOOGLE -> editor.putBoolean(key, value as Boolean) + Auth.VISIBLE -> editor.putBoolean(key, value as Boolean) + else -> throw IllegalArgumentException("Unknown key: $key") + } + } + editor.apply() + } + + private fun queryExposure(p: Array): Cursor = MatrixCursor(p).addRow(p) { key -> + when (key) { + Exposure.SCANNER_ENABLED -> getSettingsBoolean(key, false) + Exposure.LAST_CLEANUP -> preferences.getLong(key, 0L) + else -> throw IllegalArgumentException("Unknown key: $key") + } + } + + private fun updateExposure(values: ContentValues) { + if (values.size() == 0) return + val editor = preferences.edit() + values.valueSet().forEach { (key, value) -> + // TODO remove log + Log.e("TEST", "exposure update: $key = $value") + when (key) { + Exposure.SCANNER_ENABLED -> editor.putBoolean(key, value as Boolean) + Exposure.LAST_CLEANUP -> editor.putLong(key, value as Long) + else -> throw IllegalArgumentException("Unknown key: $key") + } + } + editor.apply() + } + + private fun MatrixCursor.addRow( + p: Array, + valueGetter: (String) -> Any + ): MatrixCursor { + val row = newRow() + for (key in p) row.add(valueGetter.invoke(key).apply { + // TODO remove log + Log.e("TEST", "$key = $this") + }) + return this + } + + override fun getType(uri: Uri): String { + return "vnd.android.cursor.item/vnd.$AUTHORITY.${uri.path}" + } + + override fun insert(uri: Uri, values: ContentValues?): Uri? { + throw UnsupportedOperationException() + } + + override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int { + throw UnsupportedOperationException() + } + + /** + * Returns the current setting of the given [key] + * using the default value from [systemDefaultPreferences] or [def] if not available. + * @return the current setting as [Int], because [ContentProvider] does not support [Boolean]. + */ + private fun getSettingsBoolean(key: String, def: Boolean): Int { + val default = systemDefaultPreferences?.getBoolean(key, def) ?: def + return if (preferences.getBoolean(key, default)) 1 else 0 + } +} 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 b56ec0dca221a04e8a2bc5470e65c55c6fa91769..4a59ffb482a64caba93d029476d40a87916c9ca0 100644 --- 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 @@ -34,11 +34,12 @@ class DeviceRegistrationFragment : Fragment(R.layout.device_registration_fragmen lifecycleScope.launchWhenResumed { val info = getCheckinServiceInfo(requireContext()) val newConfiguration = info.configuration.copy(enabled = newStatus) - displayServiceInfo(setCheckinServiceConfiguration(requireContext(), newConfiguration)) + setCheckinServiceConfiguration(requireContext(), newConfiguration) + displayServiceInfo(info.copy(configuration = newConfiguration)) } } - fun displayServiceInfo(serviceInfo: ServiceInfo) { + private fun displayServiceInfo(serviceInfo: ServiceInfo) { binding.checkinEnabled = serviceInfo.configuration.enabled } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt index f0e78ec22a90177eedcd79b67840ad8363dd4589..d0cb577e7283c6244f2f619f5202083a6ac9788a 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationFragment.kt @@ -33,11 +33,12 @@ class PushNotificationFragment : Fragment(R.layout.push_notification_fragment) { lifecycleScope.launchWhenResumed { val info = getGcmServiceInfo(requireContext()) val newConfiguration = info.configuration.copy(enabled = newStatus) - displayServiceInfo(setGcmServiceConfiguration(requireContext(), newConfiguration)) + setGcmServiceConfiguration(requireContext(), newConfiguration) + displayServiceInfo(info.copy(configuration = newConfiguration)) } } - fun displayServiceInfo(serviceInfo: ServiceInfo) { + private fun displayServiceInfo(serviceInfo: ServiceInfo) { binding.gcmEnabled = serviceInfo.configuration.enabled } diff --git a/play-services-cronet-core/build.gradle b/play-services-cronet-core/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..dc358f8c6910f0576577046d965649e4c4142463 --- /dev/null +++ b/play-services-cronet-core/build.gradle @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +dependencies { + implementation("org.microg:cronet-api:$cronetVersion") + implementation("org.microg:cronet-common:$cronetVersion") + implementation("org.microg:cronet-native:$cronetVersion") +} + +android { + compileSdkVersion androidCompileSdk + buildToolsVersion "$androidBuildVersionTools" + + defaultConfig { + versionName version + minSdkVersion androidMinSdk + targetSdkVersion androidTargetSdk + } + + lintOptions { + disable 'MissingTranslation' + } + + compileOptions { + sourceCompatibility = 1.8 + targetCompatibility = 1.8 + } + + buildTypes { + release {} + + releaseTest {} + + releaseDev {} + + releaseStable {} + } +} + +apply from: '../gradle/publish-android.gradle' + +description = 'microG service implementation for play-services-cronet' diff --git a/play-services-cronet-core/src/main/AndroidManifest.xml b/play-services-cronet-core/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..93245ce8862e74e383257eb25e5bf3e8c5bb01c9 --- /dev/null +++ b/play-services-cronet-core/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/play-services-cronet-core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/cronet_dynamite/ModuleDescriptor.java b/play-services-cronet-core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/cronet_dynamite/ModuleDescriptor.java new file mode 100644 index 0000000000000000000000000000000000000000..c46af5c9fa1f26d15dcf5256a7879a3243570db2 --- /dev/null +++ b/play-services-cronet-core/src/main/java/com/google/android/gms/dynamite/descriptors/com/google/android/gms/cronet_dynamite/ModuleDescriptor.java @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.dynamite.descriptors.com.google.android.gms.cronet_dynamite; + +import java.util.Arrays; +import java.util.List; + +public class ModuleDescriptor { + public static final String MODULE_ID = "com.google.android.gms.cronet_dynamite"; + public static final int MODULE_VERSION = 2; + public static final List MERGED_CLASSES = Arrays.asList( + "org.chromium.net.ApiVersion", + "org.chromium.net.BidirectionalStream", + "org.chromium.net.CallbackException", + "org.chromium.net.CronetEngine", + "org.chromium.net.CronetException", + "org.chromium.net.CronetProvider", + "org.chromium.net.ExperimentalBidirectionalStream", + "org.chromium.net.ExperimentalCronetEngine", + "org.chromium.net.ExperimentalUrlRequest", + "org.chromium.net.ICronetEngineBuilder", + "org.chromium.net.InlineExecutionProhibitedException", + "org.chromium.net.NetworkException", + "org.chromium.net.NetworkQualityRttListener", + "org.chromium.net.NetworkQualityThroughputListener", + "org.chromium.net.QuicException", + "org.chromium.net.RequestFinishedInfo", + "org.chromium.net.UploadDataProvider", + "org.chromium.net.UploadDataProviders", + "org.chromium.net.UploadDataSink", + "org.chromium.net.UrlRequest", + "org.chromium.net.UrlResponseInfo" + ); +} diff --git a/play-services-location-api/src/main/java/com/google/android/gms/location/LocationSettingsConfiguration.java b/play-services-location-api/src/main/java/com/google/android/gms/location/LocationSettingsConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..29dabea9dc0ccf9e7bd055b56401bf932c0904ce --- /dev/null +++ b/play-services-location-api/src/main/java/com/google/android/gms/location/LocationSettingsConfiguration.java @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.location; + +import org.microg.safeparcel.AutoSafeParcelable; + +public class LocationSettingsConfiguration extends AutoSafeParcelable { + @Field(1) + public String justificationText; + @Field(2) + public String experimentId; + @Field(5) + public String titleText; + + public static final Creator CREATOR = new AutoCreator<>(LocationSettingsConfiguration.class); +} diff --git a/play-services-location-api/src/main/java/com/google/android/gms/location/LocationSettingsRequest.java b/play-services-location-api/src/main/java/com/google/android/gms/location/LocationSettingsRequest.java index 517ab1c845ed5b8fbad5fd3ce29d8c567b1dab82..f77a392ef15eb821af03f8319ff9e1acdbfa768b 100644 --- a/play-services-location-api/src/main/java/com/google/android/gms/location/LocationSettingsRequest.java +++ b/play-services-location-api/src/main/java/com/google/android/gms/location/LocationSettingsRequest.java @@ -1,17 +1,6 @@ /* - * 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. + * SPDX-FileCopyrightText: 2015, microG Project Team + * SPDX-License-Identifier: Apache-2.0 */ package com.google.android.gms.location; @@ -26,27 +15,33 @@ import java.util.List; @PublicApi public class LocationSettingsRequest extends AutoSafeParcelable { - @SafeParceled(1000) + @Field(1000) private int versionCode = 2; - @SafeParceled(value = 1, subClass = LocationRequest.class) + @Field(value = 1, subClass = LocationRequest.class) @PublicApi(exclude = true) public List requests; - @SafeParceled(2) + @Field(2) @PublicApi(exclude = true) public boolean alwaysShow; + @Field(3) @PublicApi(exclude = true) public boolean needBle; + @Field(5) + @PublicApi(exclude = true) + public LocationSettingsConfiguration configuration; + private LocationSettingsRequest() { } - private LocationSettingsRequest(List requests, boolean alwaysShow, boolean needBle) { + private LocationSettingsRequest(List requests, boolean alwaysShow, boolean needBle, LocationSettingsConfiguration configuration) { this.requests = requests; this.alwaysShow = alwaysShow; this.needBle = needBle; + this.configuration = configuration; } /** @@ -79,7 +74,7 @@ public class LocationSettingsRequest extends AutoSafeParcelable { * Creates a LocationSettingsRequest that can be used with SettingsApi. */ public LocationSettingsRequest build() { - return new LocationSettingsRequest(requests, alwaysShow, needBle); + return new LocationSettingsRequest(requests, alwaysShow, needBle, null); } /** diff --git a/play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureNotificationStatusCodes.java b/play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureNotificationStatusCodes.java index 35e98886b75214ae5604790f9485fd6b26498d9c..dddea50368e6b5c41f8ae53417033f8781f7e5ef 100644 --- a/play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureNotificationStatusCodes.java +++ b/play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureNotificationStatusCodes.java @@ -21,6 +21,8 @@ public class ExposureNotificationStatusCodes extends CommonStatusCodes { public static final int FAILED_DISK_IO = 39506; public static final int FAILED_UNAUTHORIZED = 39507; public static final int FAILED_RATE_LIMITED = 39508; + public static final int FAILED_NOT_IN_FOREGROUND = 39509; + public static final int FAILED_KEY_RELEASE_NOT_PREAUTHORIZED = 39510; public static String getStatusCodeString(final int statusCode) { switch (statusCode) { @@ -42,6 +44,10 @@ public class ExposureNotificationStatusCodes extends CommonStatusCodes { return "FAILED_UNAUTHORIZED"; case FAILED_RATE_LIMITED: return "FAILED_RATE_LIMITED"; + case FAILED_NOT_IN_FOREGROUND: + return "FAILED_NOT_IN_FOREGROUND"; + case FAILED_KEY_RELEASE_NOT_PREAUTHORIZED: + return "FAILED_KEY_RELEASE_NOT_PREAUTHORIZED"; default: return CommonStatusCodes.getStatusCodeString(statusCode); } diff --git a/play-services-nearby-core-ui/src/main/AndroidManifest.xml b/play-services-nearby-core-ui/src/main/AndroidManifest.xml index fd0cbb27eeb3222b266d587a1f8571b842dea6ff..cb0f3e9bd0f145a5666ffd6bbc12d3bad54d74e4 100644 --- a/play-services-nearby-core-ui/src/main/AndroidManifest.xml +++ b/play-services-nearby-core-ui/src/main/AndroidManifest.xml @@ -9,6 +9,7 @@ + + + + @@ -40,10 +43,6 @@ - - diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationService.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationService.kt index 064e2019367ecf3f641f0a0bf1eacc85c1706c8f..d862340867584dfd6503bf3a997cb21f851fa3cd 100644 --- a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationService.kt +++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationService.kt @@ -50,7 +50,8 @@ class ExposureNotificationService : BaseService(TAG, GmsService.NEARBY_EXPOSURE) Feature("nearby_exposure_notification_get_status", 1), Feature("nearby_exposure_notification_diagnosis_keys_data_mapping", 1), Feature("nearby_exposure_notification_diagnosis_key_file_supplier", 1), - Feature("nearby_exposure_notification_package_configuration", 1) + Feature("nearby_exposure_notification_package_configuration", 1), + Feature("nearby_exposure_notification_preauthorize_key_release", 1) ) }) } diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt index ade3a23263d27f4a912fc08d3bdce4796aac7e4a..09f8e2d7a9e126ccdcc84e3f2f6e0a4b3532877c 100644 --- a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt +++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt @@ -667,7 +667,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val override fun requestPreAuthorizedTemporaryExposureKeyRelease(params: RequestPreAuthorizedTemporaryExposureKeyReleaseParams) { // TODO: Proper implementation lifecycleScope.launchSafely { - params.callback.onResult(Status.CANCELED) + params.callback.onResult(Status(FAILED_KEY_RELEASE_NOT_PREAUTHORIZED)) } } diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposurePreferences.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposurePreferences.kt index 0fdfd03c7b50496193dad00b3c4b60f3060d141f..03f4bc0afcd761e2a175cfb4918a14bb1d04a4b4 100644 --- a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposurePreferences.kt +++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposurePreferences.kt @@ -7,22 +7,23 @@ package org.microg.gms.nearby.exposurenotification import android.content.Context import android.content.Intent -import android.content.SharedPreferences -import androidx.preference.PreferenceManager -import org.microg.gms.common.PackageUtils +import org.microg.gms.settings.SettingsContract.Exposure.CONTENT_URI +import org.microg.gms.settings.SettingsContract.Exposure.LAST_CLEANUP +import org.microg.gms.settings.SettingsContract.Exposure.SCANNER_ENABLED +import org.microg.gms.settings.SettingsContract.getSettings +import org.microg.gms.settings.SettingsContract.setSettings class ExposurePreferences(private val context: Context) { - private var preferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - - init { - PackageUtils.warnIfNotPersistentProcess(ExposurePreferences::class.java) - } var enabled - get() = preferences.getBoolean(PREF_SCANNER_ENABLED, false) + get() = getSettings(context, CONTENT_URI, arrayOf(SCANNER_ENABLED)) { c -> + c.getInt(0) != 0 + } set(newStatus) { val changed = enabled != newStatus - preferences.edit().putBoolean(PREF_SCANNER_ENABLED, newStatus).commit() + setSettings(context, CONTENT_URI) { + put(SCANNER_ENABLED, newStatus) + } if (!changed) return if (newStatus) { context.sendOrderedBroadcast(Intent(context, ServiceTrigger::class.java), null) @@ -33,11 +34,11 @@ class ExposurePreferences(private val context: Context) { } var lastCleanup - get() = preferences.getLong(PREF_LAST_CLEANUP, 0) - set(value) = preferences.edit().putLong(PREF_LAST_CLEANUP, value).apply() + get() = getSettings(context, CONTENT_URI, arrayOf(LAST_CLEANUP)) { c -> + c.getLong(0) + } + set(value) = setSettings(context, CONTENT_URI) { + put(LAST_CLEANUP, value) + } - companion object { - private const val PREF_SCANNER_ENABLED = "exposure_scanner_enabled" - private const val PREF_LAST_CLEANUP = "exposure_last_cleanup" - } } diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ServiceInfo.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ServiceInfo.kt index 1379e9cee2854c641e9ec9c49e2a1dcac25d4967..602dc738667d2973f91209294ce59adc68acf789 100644 --- a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ServiceInfo.kt +++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ServiceInfo.kt @@ -5,21 +5,10 @@ package org.microg.gms.nearby.exposurenotification -import android.content.BroadcastReceiver import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import android.util.Log +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import java.io.Serializable -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine - -private const val ACTION_SERVICE_INFO_REQUEST = "org.microg.gms.nearby.exposurenotification.SERVICE_INFO_REQUEST" -private const val ACTION_UPDATE_CONFIGURATION = "org.microg.gms.nearby.exposurenotification.UPDATE_CONFIGURATION" -private const val ACTION_SERVICE_INFO_RESPONSE = "org.microg.gms.nearby.exposurenotification.SERVICE_INFO_RESPONSE" -private const val EXTRA_SERVICE_INFO = "org.microg.gms.nearby.exposurenotification.SERVICE_INFO" -private const val EXTRA_CONFIGURATION = "org.microg.gms.nearby.exposurenotification.CONFIGURATION" data class ServiceInfo(val configuration: ServiceConfiguration) : Serializable @@ -31,59 +20,12 @@ data class ServiceConfiguration(val enabled: Boolean) : Serializable { private fun ExposurePreferences.toConfiguration(): ServiceConfiguration = ServiceConfiguration(enabled) -class ServiceInfoReceiver : BroadcastReceiver() { - private fun sendInfoResponse(context: Context) { - context.sendOrderedBroadcast(Intent(ACTION_SERVICE_INFO_RESPONSE).apply { - setPackage(context.packageName) - putExtra(EXTRA_SERVICE_INFO, ServiceInfo(ExposurePreferences(context).toConfiguration())) - }, null) - } - - override fun onReceive(context: Context, intent: Intent) { - try { - when (intent.action) { - ACTION_UPDATE_CONFIGURATION -> { - (intent.getSerializableExtra(EXTRA_CONFIGURATION) as? ServiceConfiguration)?.saveToPrefs(context) - } - } - sendInfoResponse(context) - } catch (e: Exception) { - Log.w(TAG, e) - } +suspend fun getExposureNotificationsServiceInfo(context: Context): ServiceInfo = + withContext(Dispatchers.IO) { + ServiceInfo(ExposurePreferences(context).toConfiguration()) } -} -private suspend fun sendToServiceInfoReceiver(intent: Intent, context: Context): ServiceInfo = suspendCoroutine { - context.registerReceiver(object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - context.unregisterReceiver(this) - val serviceInfo = try { - intent.getSerializableExtra(EXTRA_SERVICE_INFO) as ServiceInfo - } catch (e: Exception) { - it.resumeWithException(e) - return - } - try { - it.resume(serviceInfo) - } catch (e: Exception) { - Log.w(TAG, e) - } - } - }, IntentFilter(ACTION_SERVICE_INFO_RESPONSE)) - try { - context.sendOrderedBroadcast(intent, null) - } catch (e: Exception) { - it.resumeWithException(e) +suspend fun setExposureNotificationsServiceConfiguration(context: Context, configuration: ServiceConfiguration) = + withContext(Dispatchers.IO) { + ExposurePreferences(context).enabled = configuration.enabled } -} - -suspend fun getExposureNotificationsServiceInfo(context: Context): ServiceInfo = sendToServiceInfoReceiver( - Intent(context, ServiceInfoReceiver::class.java).apply { - action = ACTION_SERVICE_INFO_REQUEST - }, context) - -suspend fun setExposureNotificationsServiceConfiguration(context: Context, configuration: ServiceConfiguration): ServiceInfo = sendToServiceInfoReceiver( - Intent(context, ServiceInfoReceiver::class.java).apply { - action = ACTION_UPDATE_CONFIGURATION - putExtra(EXTRA_CONFIGURATION, configuration) - }, context) diff --git a/play-services-tapandpay-api/build.gradle b/play-services-tapandpay-api/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..123421995eaa8f840e0a8a50fc6a088556a26f5e --- /dev/null +++ b/play-services-tapandpay-api/build.gradle @@ -0,0 +1,46 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +android { + compileSdkVersion androidCompileSdk + buildToolsVersion "$androidBuildVersionTools" + + defaultConfig { + versionName version + minSdkVersion androidMinSdk + targetSdkVersion androidTargetSdk + } + + compileOptions { + sourceCompatibility = 1.8 + targetCompatibility = 1.8 + } + + buildTypes { + release {} + + releaseTest {} + + releaseDev {} + + releaseStable {} + } +} + +// Nothing to publish yet +//apply from: '../gradle/publish-android.gradle' + +description = 'microG API for play-services-tapandpay' + +dependencies { + api project(':play-services-basement') + api project(':play-services-base-api') + + implementation "androidx.annotation:annotation:$annotationVersion" +} diff --git a/play-services-tapandpay-api/src/main/AndroidManifest.xml b/play-services-tapandpay-api/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..0b3e189bbf7cc0b1d0a0ed4bde72432adb69b608 --- /dev/null +++ b/play-services-tapandpay-api/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + diff --git a/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/firstparty/TokenStatus.aidl b/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/firstparty/TokenStatus.aidl new file mode 100644 index 0000000000000000000000000000000000000000..16841b3f30216e14bc1db3c0dfddff86400273b4 --- /dev/null +++ b/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/firstparty/TokenStatus.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.tapandpay.firstparty; + +parcelable TokenStatus; diff --git a/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/internal/ITapAndPayService.aidl b/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/internal/ITapAndPayService.aidl new file mode 100644 index 0000000000000000000000000000000000000000..9ee5001000896d47bee52f76c9ec09d5e94bba15 --- /dev/null +++ b/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/internal/ITapAndPayService.aidl @@ -0,0 +1,39 @@ +package com.google.android.gms.tapandpay.internal; + +import com.google.android.gms.tapandpay.internal.ITapAndPayServiceCallbacks; + +interface ITapAndPayService { +// void setSelectedToken(in SetSelectedTokenRequest request, ITapAndPayServiceCallbacks callbacks) = 0; +// void getAllCards(in GetAllCardsRequest request, ITapAndPayServiceCallbacks callbacks) = 1; +// void deleteToken(in DeleteTokenRequest request, ITapAndPayServiceCallbacks callbacks) = 2; +// void firstPartyTokenizePan(in FirstPartyTokenizePanRequest request, ITapAndPayServiceCallbacks callbacks) = 3; +// void setActiveAccount(in SetActiveAccountRequest request, ITapAndPayServiceCallbacks callbacks) = 4; +// void showSecurityPrompt(in ShowSecurityPromptRequest request, ITapAndPayServiceCallbacks callbacks) = 7; +// void getActiveAccount(in GetActiveAccountRequest request, ITapAndPayServiceCallbacks callbacks) = 8; + void registerDataChangedListener(ITapAndPayServiceCallbacks callbacks) = 9; +// void isDeviceUnlockedForPayment(in IsDeviceUnlockedForPaymentRequest request, ITapAndPayServiceCallbacks callbacks) = 10; +// void promptDeviceUnlockForPayment(in PromptDeviceUnlockForPaymentRequest request, ITapAndPayServiceCallbacks callbacks) = 11; +// void sendTapEvent(in SendTapEventRequest request, ITapAndPayServiceCallbacks callbacks) = 12; +// void getReceivesTransactionNotification(in GetReceivesTransactionNotificationsRequest request, ITapAndPayServiceCallbacks callbacks) = 13; +// void setReceivesTransactionNotification(in SetReceivesTransactionNotificationsRequest request, ITapAndPayServiceCallbacks callbacks) = 14; +// void retrieveInAppPaymentCredential(in RetrieveInAppPaymentCredentialRequest request, ITapAndPayServiceCallbacks callbacks) = 15; +// void getActiveCardsForAccount(in GetActiveCardsForAccountRequest request, ITapAndPayServiceCallbacks callbacks) = 17; +// void getAnalyticsContext(ITapAndPayServiceCallbacks callbacks) = 19; +// void getActiveWalletId(ITapAndPayServiceCallbacks callbacks) = 20; + void getTokenStatus(int tokenProvider, String issuerTokenId, ITapAndPayServiceCallbacks callbacks) = 21; +// void issuerTokenize(int tokenProvider, String issuerTokenId, String s2, ITapAndPayServiceCallbacks callbacks) = 22; +// void requestSelectToken(int tokenProvider, String issuerTokenId, ITapAndPayServiceCallbacks callbacks) = 23; +// void requestDeleteToken(int tokenProvider, String issuerTokenId, ITapAndPayServiceCallbacks callbacks) = 24; +// void isDeviceUnlockedForInAppPayment(in IsDeviceUnlockedForInAppPaymentRequest request, ITapAndPayServiceCallbacks callbacks) = 25; +// void reportInAppTransactionCompleted(in ReportInAppTransactionCompletedRequest request, ITapAndPayServiceCallbacks callbacks) = 26; +// void pushTokenize(in PushTokenizeRequest request, ITapAndPayServiceCallbacks callbacks) = 27; +// void createWallet(ITapAndPayServiceCallbacks callbacks) = 28; + void getStableHardwareId(ITapAndPayServiceCallbacks callbacks) = 29; +// void getEnvironment(ITapAndPayServiceCallbacks callbacks) = 30; +// void enablePayOnWear(in EnablePayOnWearRequest request, ITapAndPayServiceCallbacks callbacks) = 31; +// void isPayPalAvailable(ITapAndPayServiceCallbacks callbacks) = 32; +// void unknown34(ITapAndPayServiceCallbacks callbacks) = 33; +// void getSecurityParams(ITapAndPayServiceCallbacks callbacks) = 34; +// void getNotificationSettings(in GetNotificationSettingsRequest request, ITapAndPayServiceCallbacks callbacks) = 36; +// void setNotificationSettings(in SetNotificationSettingsRequest request, ITapAndPayServiceCallbacks callbacks) = 37; +} diff --git a/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/internal/ITapAndPayServiceCallbacks.aidl b/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/internal/ITapAndPayServiceCallbacks.aidl new file mode 100644 index 0000000000000000000000000000000000000000..980d3657b66d9da6735af4632d134ea2a2bc9a86 --- /dev/null +++ b/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/internal/ITapAndPayServiceCallbacks.aidl @@ -0,0 +1,47 @@ +package com.google.android.gms.tapandpay.internal; + +import com.google.android.gms.common.api.Status; +import com.google.android.gms.tapandpay.issuer.TokenStatus; + +interface ITapAndPayServiceCallbacks { + void onSetSelectedTokenResponse(in Status status) = 1; + void onStatus3(in Status status, in Bundle data) = 2; +// void onGetAllCardsResponse(in Status status, in GetAllCardsResponse response) = 3; + void onDeleteTokenResponse(in Status status) = 4; + void onSetActiveAccountResponse(in Status status) = 5; +// void onGetActiveAccountResponse(in Status status, in GetActiveAccountResponse response) = 7; + void onStatus9(in Status status) = 8; + void onReturn10() = 9; + void onIsDeviceUnlockedForPaymentResponse(in Status status, boolean isDeviceUnlockedForPayment) = 10; + void onStatus12(in Status status) = 11; + void onGetReceivesTransactionNotificationsResponse(in Status status, boolean receivesTransactionNotifications) = 12; + void onSetReceivesTransactionNotificationsResponse(in Status status) = 13; +// void onGetActiveCardsForAccountResponse(in Status status, in GetActiveCardsForAccountResponse response) = 14; +// void onRetrieveInAppPaymentCredentialResponse(in Status status, in RetrieveInAppPaymentCredentialResponse response) = 16; + void onGetAnalyticsContextResponse(in Status status, String analyticsContext) = 17; + void onTokenStatus(in Status status, in TokenStatus tokenStatus) = 19; + void onIsDeviceUnlockedForInAppPaymentResponse(in Status status, boolean isDeviceUnlockedForInAppPayment) = 20; + void onReportInAppTransactionCompletedResponse(in Status status) = 21; + void onGetStableHardwareIdResponse(in Status status, String stableHardwareId) = 22; + void onGetEnvironmentResponse(in Status status, String env) = 23; + void onEnablePayOnWearResponse(in Status status) = 24; + void onIsPayPalAvailableResponse(in Status status, boolean IsPayPalAvailable) = 25; +// void onGetSecurityParamsResponse(in Status status, in GetSecurityParamsResponse response) = 26; +// void onGetNotificationSettingsResponse(in Status status, in GetNotificationSettingsResponse response) = 27; + void onSetNotificationSettingsResponse(in Status status) = 28; +// void onGetAvailableOtherPaymentMethodsResponse(in Status status, in GetAvailableOtherPaymentMethodsResponse response) = 29; +// void onGetActiveTokensForAccountResponse(in Status status, in GetActiveTokensForAccountResponse response) = 30; +// void onGetSeChipTransactionsResponse(in Status status, in GetSeChipTransactionsResponse response) = 34; +// void onReserveResourceResponse(in Status status, in ReserveResourceResponse response) = 35; + void onReleaseResourceResponse(in Status status) = 36; + void onDisableSelectedTokenResponse(in Status status) = 37; +// void onGetFelicaTosAcceptanceResponse(in Status status, in GetFelicaTosAcceptanceResponse response) = 38; + void onSetFelicaTosAcceptanceResponse(in Status status) = 39; +// void onRefreshSeCardsResponse(in Status status, in RefreshSeCardsResponse response) = 40; +// void onGetGlobalActionCardsResponse(in Status status, in GetGlobalActionCardsResponse response) = 41; + void onGetLinkingTokenResponse(in Status status, String linkingToken) = 42; + void onBlockPaymentCardsResponse(in Status status) = 43; + void onUnblockPaymentCardsResponse(in Status status) = 44; +// void onGetLastAttestationResultResponse(in Status status, in GetLastAttestationResultResponse response) = 45; +// void onQuickAccessWalletConfig(in Status status, in QuickAccessWalletConfig config) = 46; +} diff --git a/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/issuer/TokenStatus.aidl b/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/issuer/TokenStatus.aidl new file mode 100644 index 0000000000000000000000000000000000000000..b23fc9974ae1deb489d5276a726238af93daf97b --- /dev/null +++ b/play-services-tapandpay-api/src/main/aidl/com/google/android/gms/tapandpay/issuer/TokenStatus.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.tapandpay.issuer; + +parcelable TokenStatus; diff --git a/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/TapAndPayStatusCodes.java b/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/TapAndPayStatusCodes.java new file mode 100644 index 0000000000000000000000000000000000000000..368c58d81ae6719461df6c91860c27bfefd9d32d --- /dev/null +++ b/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/TapAndPayStatusCodes.java @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.tapandpay; + +import com.google.android.gms.common.api.CommonStatusCodes; + +import org.microg.gms.common.PublicApi; + +@PublicApi +public class TapAndPayStatusCodes extends CommonStatusCodes { + public static final int TAP_AND_PAY_NO_ACTIVE_WALLET = 15002; + public static final int TAP_AND_PAY_TOKEN_NOT_FOUND = 15003; + public static final int TAP_AND_PAY_INVALID_TOKEN_STATE = 15004; + public static final int TAP_AND_PAY_ATTESTATION_ERROR = 15005; + public static final int TAP_AND_PAY_UNAVAILABLE = 15009; +} diff --git a/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/firstparty/TokenReference.java b/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/firstparty/TokenReference.java new file mode 100644 index 0000000000000000000000000000000000000000..cd04c6623a4502ca90fe50f511b04bf65a4a2a29 --- /dev/null +++ b/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/firstparty/TokenReference.java @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.tapandpay.firstparty; + +import org.microg.safeparcel.AutoSafeParcelable; + +public class TokenReference extends AutoSafeParcelable { + @Field(2) + public String tokenReferenceId; + @Field(3) + public int tokenProvider; + + public static final Creator CREATOR = new AutoCreator<>(TokenReference.class); +} diff --git a/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/firstparty/TokenStatus.java b/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/firstparty/TokenStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..213a804d1cbfe8898b6348c69b5677e2075b83e3 --- /dev/null +++ b/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/firstparty/TokenStatus.java @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.tapandpay.firstparty; + +import org.microg.safeparcel.AutoSafeParcelable; + +public class TokenStatus extends AutoSafeParcelable { + @Field(2) + public TokenReference tokenReference; + @Field(3) + public int tokenState; + @Field(4) + public boolean isSelected; + + public static final Creator CREATOR = new AutoCreator<>(TokenStatus.class); +} diff --git a/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/issuer/TokenStatus.java b/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/issuer/TokenStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..e4429af91849a8befc10dab238e8951ba6fd2983 --- /dev/null +++ b/play-services-tapandpay-api/src/main/java/com/google/android/gms/tapandpay/issuer/TokenStatus.java @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.tapandpay.issuer; + +import org.microg.gms.common.PublicApi; +import org.microg.safeparcel.AutoSafeParcelable; + +@PublicApi +public class TokenStatus extends AutoSafeParcelable { + @Field(2) + @PublicApi(exclude = true) + public String issuerTokenId; + @Field(3) + @PublicApi(exclude = true) + private int tokenState; + @Field(4) + @PublicApi(exclude = true) + private boolean isSelected; + + public int getTokenState() { + return tokenState; + } + + public boolean isSelected() { + return isSelected; + } + + public static final Creator CREATOR = new AutoCreator<>(TokenStatus.class); +} diff --git a/play-services-tapandpay-core/build.gradle b/play-services-tapandpay-core/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..94925504f75251e1a0f9f6270012cee496988e0d --- /dev/null +++ b/play-services-tapandpay-core/build.gradle @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +dependencies { + api project(':play-services-tapandpay-api') + + implementation project(':play-services-base-core') + + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion" +} + +android { + compileSdkVersion androidCompileSdk + buildToolsVersion "$androidBuildVersionTools" + + defaultConfig { + versionName version + minSdkVersion androidMinSdk + targetSdkVersion androidTargetSdk + } + + sourceSets { + main { + java.srcDirs = ['src/main/kotlin'] + } + } + + lintOptions { + disable 'MissingTranslation' + } + + compileOptions { + sourceCompatibility = 1.8 + targetCompatibility = 1.8 + } + + buildTypes { + release {} + + releaseTest {} + + releaseDev {} + + releaseStable {} + } +} + +// Nothing to publish yet +//apply from: '../gradle/publish-android.gradle' + +description = 'microG service implementation for play-services-tapandpay' diff --git a/play-services-tapandpay-core/src/main/AndroidManifest.xml b/play-services-tapandpay-core/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..64ee486c4a4604520ad45c9cfa1f800b19875cbf --- /dev/null +++ b/play-services-tapandpay-core/src/main/AndroidManifest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/play-services-tapandpay-core/src/main/kotlin/org/microg/gms/tapandpay/TapAndPayService.kt b/play-services-tapandpay-core/src/main/kotlin/org/microg/gms/tapandpay/TapAndPayService.kt new file mode 100644 index 0000000000000000000000000000000000000000..0a08696b0518e71e6643c4018f53a5dd2523edbc --- /dev/null +++ b/play-services-tapandpay-core/src/main/kotlin/org/microg/gms/tapandpay/TapAndPayService.kt @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ +package org.microg.gms.tapandpay + +import android.os.Parcel +import android.os.RemoteException +import android.util.Log +import com.google.android.gms.common.api.CommonStatusCodes +import com.google.android.gms.common.api.Status +import com.google.android.gms.common.internal.GetServiceRequest +import com.google.android.gms.common.internal.IGmsCallbacks +import com.google.android.gms.tapandpay.TapAndPayStatusCodes.TAP_AND_PAY_NO_ACTIVE_WALLET +import com.google.android.gms.tapandpay.internal.ITapAndPayService +import com.google.android.gms.tapandpay.internal.ITapAndPayServiceCallbacks +import org.microg.gms.BaseService +import org.microg.gms.common.GmsService + +private const val TAG = "GmsTapAndPay" + +class TapAndPayService : BaseService(TAG, GmsService.TAP_AND_PAY) { + override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) { + callback.onPostInitComplete(CommonStatusCodes.SUCCESS, TapAndPayImpl(), null) + } +} + +class TapAndPayImpl : ITapAndPayService.Stub() { + override fun registerDataChangedListener(callbacks: ITapAndPayServiceCallbacks) { + Log.d(TAG, "registerDataChangedListener()") + callbacks.onStatus9(Status.SUCCESS) + } + + override fun getTokenStatus(tokenProvider: Int, issuerTokenId: String, callbacks: ITapAndPayServiceCallbacks) { + Log.d(TAG, "getTokenStatus($tokenProvider, $issuerTokenId)") + callbacks.onTokenStatus(Status(TAP_AND_PAY_NO_ACTIVE_WALLET), null) + } + + override fun getStableHardwareId(callbacks: ITapAndPayServiceCallbacks) { + Log.d(TAG, "getStableHardwareId()") + callbacks.onGetStableHardwareIdResponse(Status.SUCCESS, "") + } + + override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean { + if (super.onTransact(code, data, reply, flags)) return true + Log.d(TAG, "onTransact [unknown]: $code, $data, $flags") + return false + } +} diff --git a/settings.gradle b/settings.gradle index 2d79cb32d9a472f69acf65d9f97c412de6d4cd9a..ef4eb297202a80780e9643c5b21aee15ce7c2dc3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,6 +10,7 @@ include ':play-services-droidguard-api' include ':play-services-iid-api' include ':play-services-location-api' include ':play-services-nearby-api' +include ':play-services-tapandpay-api' include ':play-services-vision-api' include ':play-services-vision-common-api' include ':play-services-wearable-api' @@ -24,11 +25,13 @@ include ':play-services-wearable-proto' include ':play-services-base-core' include ':play-services-conscrypt-provider-core' +include ':play-services-cronet-core' include ':play-services-location-core' include ':play-services-maps-core-mapbox' include ':play-services-maps-core-vtm' include ':play-services-maps-core-vtm:vtm-microg-theme' include ':play-services-nearby-core' +include ':play-services-tapandpay-core' include ':play-services-vision-core' include ':play-services-base-core-ui'