diff --git a/build.gradle b/build.gradle index c29bbe04..3f174192 100644 --- a/build.gradle +++ b/build.gradle @@ -45,8 +45,8 @@ allprojects { apply plugin: 'idea' group = 'org.microg.gms' - version = "0.2.14.204218" - ext.appVersionCode = 204215004 + version = "0.2.16.204713" + ext.appVersionCode = 204713001 ext.isReleaseVersion = false } diff --git a/play-services-basement/build.gradle b/play-services-basement/build.gradle index 0eebf799..246534d0 100644 --- a/play-services-basement/build.gradle +++ b/play-services-basement/build.gradle @@ -19,7 +19,7 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' dependencies { - api "org.microg:safe-parcel:$safeParcelVersion" + api "org.microg:safe-parcel:1.7.0" implementation "androidx.annotation:annotation:$annotationVersion" implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.21' diff --git a/play-services-basement/src/main/java/org/microg/gms/common/GmsService.java b/play-services-basement/src/main/java/org/microg/gms/common/GmsService.java index d0130ab2..760ae244 100644 --- a/play-services-basement/src/main/java/org/microg/gms/common/GmsService.java +++ b/play-services-basement/src/main/java/org/microg/gms/common/GmsService.java @@ -46,6 +46,7 @@ public enum GmsService { CREDENTIALS(68, "com.google.android.gms.auth.api.credentials.service.START"), MEASUREMENT(93, "com.google.android.gms.measurement.START"), GASS(116, "com.google.android.gms.gass.START"), + IDENTITY_SIGN_IN(212, "com.google.android.gms.auth.api.identity.service.signin.START"), ; public int SERVICE_ID; @@ -65,6 +66,15 @@ public enum GmsService { return UNKNOWN; } + public static GmsService byAction(String action) { + for (GmsService service : values()) { + for (String serviceAction : service.SECONDARY_ACTIONS) { + if (serviceAction.equals(action)) return service; + } + } + return UNKNOWN; + } + public static String nameFromServiceId(int serviceId) { return byServiceId(serviceId).toString(serviceId); } diff --git a/play-services-core/src/main/AndroidManifest.xml b/play-services-core/src/main/AndroidManifest.xml index fcdb9473..5e323cd7 100644 --- a/play-services-core/src/main/AndroidManifest.xml +++ b/play-services-core/src/main/AndroidManifest.xml @@ -80,9 +80,10 @@ tools:ignore="ProtectedPermissions" /> @@ -144,7 +145,8 @@ + android:name="org.microg.gms.gcm.PushRegisterService" + android:process=":persistent"> @@ -153,24 +155,33 @@ - + - + + android:name="org.microg.gms.gcm.SendReceiver" + android:process=":persistent"> - + - + @@ -191,7 +202,9 @@ - + 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 index 3c631b96..e5d64db4 100755 --- 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 @@ -22,9 +22,7 @@ public class CheckinPrefs implements SharedPreferences.OnSharedPreferenceChangeL public static CheckinPrefs get(Context context) { if (INSTANCE == null) { - if (!context.getPackageName().equals(PackageUtils.getProcessName())) { - Log.w("Preferences", CheckinPrefs.class.getName() + " initialized outside main process", new RuntimeException()); - } + PackageUtils.warnIfNotMainProcess(context, CheckinPrefs.class); if (context == null) return new CheckinPrefs(null); INSTANCE = new CheckinPrefs(context.getApplicationContext()); } 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 adb2399e..56c273b9 100755 --- a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinService.java +++ b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinService.java @@ -32,13 +32,16 @@ import android.util.Log; import androidx.legacy.content.WakefulBroadcastReceiver; +import com.mgoogle.android.gms.R; import com.google.android.gms.checkin.internal.ICheckinService; import org.microg.gms.auth.AuthConstants; +import org.microg.gms.common.ForegroundServiceInfo; import org.microg.gms.common.ForegroundServiceContext; import org.microg.gms.gcm.McsService; import org.microg.gms.people.PeopleManager; +@ForegroundServiceInfo(value = "Google device registration", res = R.string.service_name_checkin) public class CheckinService extends IntentService { private static final String TAG = "GmsCheckinSvc"; public static final long MAX_VALID_CHECKIN_AGE = 24 * 60 * 60 * 1000; // 12 hours diff --git a/play-services-core/src/main/java/org/microg/gms/common/ForegroundServiceContext.java b/play-services-core/src/main/java/org/microg/gms/common/ForegroundServiceContext.java index 81cf78b4..352e9905 100644 --- a/play-services-core/src/main/java/org/microg/gms/common/ForegroundServiceContext.java +++ b/play-services-core/src/main/java/org/microg/gms/common/ForegroundServiceContext.java @@ -48,16 +48,46 @@ public class ForegroundServiceContext extends ContextWrapper { return powerManager.isIgnoringBatteryOptimizations(getPackageName()); } + private static String getServiceName(Service service) { + String serviceName = null; + try { + ForegroundServiceInfo annotation = service.getClass().getAnnotation(ForegroundServiceInfo.class); + if (annotation != null) { + if (annotation.res() != 0) { + try { + serviceName = service.getString(annotation.res()); + } catch (Exception ignored) { + } + } + if (serviceName == null) { + serviceName = annotation.value(); + } + } + } catch (Exception ignored) { + } + if (serviceName == null) { + serviceName = service.getClass().getSimpleName(); + } + return serviceName; + } + public static void completeForegroundService(Service service, Intent intent, String tag) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && intent != null && intent.getBooleanExtra(EXTRA_FOREGROUND, false)) { - Log.d(tag, "Started in foreground mode."); - service.startForeground(tag.hashCode(), buildForegroundNotification(service)); + String serviceName = getServiceName(service); + Log.d(tag, "Started " + serviceName + " in foreground mode."); + try { + Notification notification = buildForegroundNotification(service, serviceName); + service.startForeground(serviceName.hashCode(), notification); + Log.d(tag, "Notification: " + notification.toString()); + } catch (Exception e) { + Log.w(tag, e); + } } } - private static Notification buildForegroundNotification(Context context) { + private static Notification buildForegroundNotification(Context context, String serviceName) { Intent notificationIntent = new Intent(); notificationIntent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS); notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -70,6 +100,7 @@ public class ForegroundServiceContext extends ContextWrapper { context.getResources().getString(R.string.notification_service_name), NotificationManager.IMPORTANCE_LOW); Channel.setShowBadge(false); + Channel.setVibrationPattern(new long[]{0}); Channel.setLockscreenVisibility(0); context.getSystemService(NotificationManager.class).createNotificationChannel(Channel); } diff --git a/play-services-core/src/main/java/org/microg/gms/common/ForegroundServiceInfo.java b/play-services-core/src/main/java/org/microg/gms/common/ForegroundServiceInfo.java new file mode 100644 index 00000000..8a8102a6 --- /dev/null +++ b/play-services-core/src/main/java/org/microg/gms/common/ForegroundServiceInfo.java @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.common; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ForegroundServiceInfo { + String value(); + int res() default 0; +} \ No newline at end of file diff --git a/play-services-core/src/main/java/org/microg/gms/common/PackageUtils.java b/play-services-core/src/main/java/org/microg/gms/common/PackageUtils.java index f726bcec..c7a6fc8d 100644 --- a/play-services-core/src/main/java/org/microg/gms/common/PackageUtils.java +++ b/play-services-core/src/main/java/org/microg/gms/common/PackageUtils.java @@ -24,6 +24,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; import android.os.Binder; +import android.util.Log; import androidx.annotation.Nullable; @@ -255,6 +256,36 @@ public class PackageUtils { } } + public static boolean isPersistentProcess() { + String processName = getProcessName(); + if (processName == null) { + Log.w("GmsPackageUtils", "Can't determine process name of current process"); + return false; + } + return processName.endsWith(":persistent"); + } + + public static boolean isMainProcess(Context context) { + String processName = getProcessName(); + if (processName == null) { + Log.w("GmsPackageUtils", "Can't determine process name of current process"); + return false; + } + return processName.equals(context.getPackageName()); + } + + public static void warnIfNotPersistentProcess(Class clazz) { + if (!isPersistentProcess()) { + Log.w("GmsPackageUtils", clazz.getSimpleName() + " initialized outside persistent process", new RuntimeException()); + } + } + + public static void warnIfNotMainProcess(Context context, Class clazz) { + if (!isMainProcess(context)) { + Log.w("GmsPackageUtils", clazz.getSimpleName() + " initialized outside main process", new RuntimeException()); + } + } + public static String sha1sum(byte[] bytes) { MessageDigest md; try { 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 index 95034f3d..c80e80ab 100644 --- 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 @@ -53,10 +53,7 @@ public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListe public static GcmPrefs get(Context context) { if (INSTANCE == null) { - if (!context.getPackageName().equals(PackageUtils.getProcessName())) { - Log.w("Preferences", GcmPrefs.class.getName() + " initialized outside main process", new RuntimeException()); - } - if (context == null) return new GcmPrefs(null); + PackageUtils.warnIfNotPersistentProcess(GcmPrefs.class); INSTANCE = new GcmPrefs(context.getApplicationContext()); } return INSTANCE; @@ -64,7 +61,6 @@ public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListe private boolean gcmLogEnabled = true; private String lastPersistedId = ""; - private boolean confirmNewApps = false; private boolean gcmEnabled = false; private int networkMobile = 0; @@ -76,19 +72,19 @@ public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListe private int learntMobile = 300000; private int learntOther = 300000; + private final Context context; private SharedPreferences preferences; private SharedPreferences systemDefaultPreferences; private GcmPrefs(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(); + 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) { @@ -101,7 +97,6 @@ public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListe public void update() { gcmEnabled = getSettingsBoolean(PREF_ENABLE_GCM, true); gcmLogEnabled = getSettingsBoolean(PREF_FULL_LOG, true); - confirmNewApps = getSettingsBoolean(PREF_CONFIRM_NEW_APPS, false); lastPersistedId = preferences.getString(PREF_LAST_PERSISTENT_ID, ""); @@ -129,12 +124,49 @@ public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListe } public int getHeartbeatMsFor(NetworkInfo info) { - return getHeartbeatMsFor(getNetworkPrefForInfo(info), false); + return getHeartbeatMsFor(getNetworkPrefForInfo(info)); } - public int getHeartbeatMsFor(String pref, boolean rawRoaming) { - if (PREF_NETWORK_ROAMING.equals(pref) && (rawRoaming || networkRoaming != 0)) { - return networkRoaming * 60000; + 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; @@ -201,6 +233,18 @@ public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListe preferences.edit().putInt(PREF_LEARNT_MOBILE, INTERVAL).putInt(PREF_LEARNT_WIFI, INTERVAL).putInt(PREF_LEARNT_OTHER, INTERVAL).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(); @@ -210,27 +254,23 @@ public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListe return gcmEnabled; } - public boolean isEnabledFor(NetworkInfo info) { - return isEnabled() && info != null && getHeartbeatMsFor(info) >= 0; - } - - public static void setEnabled(Context context, boolean newStatus) { - boolean changed = GcmPrefs.get(context).isEnabled() != newStatus; - PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(GcmPrefs.PREF_ENABLE_GCM, newStatus).apply(); + public void setEnabled(boolean value) { + boolean changed = gcmEnabled != value; + preferences.edit().putBoolean(GcmPrefs.PREF_ENABLE_GCM, value).apply(); if (!changed) return; - if (!newStatus) { + if (!value) { McsService.stop(context); } else { context.sendBroadcast(new Intent(TriggerReceiver.FORCE_TRY_RECONNECT, null, context, TriggerReceiver.class)); } } - public boolean isGcmLogEnabled() { - return gcmLogEnabled; + public boolean isEnabledFor(NetworkInfo info) { + return isEnabled() && info != null && getHeartbeatMsFor(info) >= 0; } - public boolean isConfirmNewApps() { - return confirmNewApps; + public boolean isGcmLogEnabled() { + return gcmLogEnabled; } public List getLastPersistedIds() { 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 0f78a756..cdf5b3ca 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 @@ -40,10 +40,12 @@ import android.util.Log; import androidx.legacy.content.WakefulBroadcastReceiver; +import com.mgoogle.android.gms.R; import com.squareup.wire.Message; import org.microg.gms.checkin.LastCheckinInfo; import org.microg.gms.common.ForegroundServiceContext; +import org.microg.gms.common.ForegroundServiceInfo; import org.microg.gms.common.PackageUtils; import org.microg.gms.gcm.mcs.AppData; import org.microg.gms.gcm.mcs.Close; @@ -106,6 +108,7 @@ import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_ERROR; import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_READY; import static org.microg.gms.gcm.McsConstants.MSG_TEARDOWN; +@ForegroundServiceInfo(value = "Cloud messaging", res = R.string.service_name_mcs) public class McsService extends Service implements Handler.Callback { private static final String TAG = "GmsGcmMcsSvc"; @@ -236,7 +239,7 @@ public class McsService extends Service implements Handler.Callback { return false; } // consider connection to be dead if we did not receive an ack within twice the heartbeat interval - int heartbeatMs = GcmPrefs.get(context).getHeartbeatMsFor(activeNetworkPref, false); + int heartbeatMs = GcmPrefs.get(context).getHeartbeatMsFor(activeNetworkPref); if (heartbeatMs < 0) { closeAll(); } else if (SystemClock.elapsedRealtime() - lastHeartbeatAckElapsedRealtime > 2 * heartbeatMs) { @@ -266,7 +269,7 @@ public class McsService extends Service implements Handler.Callback { public void scheduleHeartbeat(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE); - int heartbeatMs = GcmPrefs.get(this).getHeartbeatMsFor(activeNetworkPref, false); + int heartbeatMs = GcmPrefs.get(this).getHeartbeatMsFor(activeNetworkPref); if (heartbeatMs < 0) { closeAll(); } 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 b3ffca9e..3c1846f3 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,7 @@ 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).lastCheckin <= 0) { 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/gservices/GServicesProvider.java b/play-services-core/src/main/java/org/microg/gms/gservices/GServicesProvider.java index 324ce4dd..d5245318 100644 --- a/play-services-core/src/main/java/org/microg/gms/gservices/GServicesProvider.java +++ b/play-services-core/src/main/java/org/microg/gms/gservices/GServicesProvider.java @@ -55,8 +55,6 @@ public class GServicesProvider extends ContentProvider { @Override public boolean onCreate() { - databaseHelper = new DatabaseHelper(getContext()); - if (CheckinPrefs.get(getContext()).isEnabled()) { getContext().sendOrderedBroadcast(new Intent(getContext(), org.microg.gms.checkin.TriggerReceiver.class), null); } @@ -64,6 +62,7 @@ public class GServicesProvider extends ContentProvider { getContext().sendBroadcast(new Intent(org.microg.gms.gcm.TriggerReceiver.FORCE_TRY_RECONNECT, null, getContext(), org.microg.gms.gcm.TriggerReceiver.class)); } + databaseHelper = new DatabaseHelper(getContext()); return true; } diff --git a/play-services-core/src/main/java/org/microg/gms/ui/GcmAdvancedFragment.java b/play-services-core/src/main/java/org/microg/gms/ui/GcmAdvancedFragment.java deleted file mode 100755 index b7a65edb..00000000 --- a/play-services-core/src/main/java/org/microg/gms/ui/GcmAdvancedFragment.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 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.ui; - -import android.content.Intent; -import android.os.Bundle; - -import androidx.annotation.Nullable; -import androidx.preference.Preference; - -import com.mgoogle.android.gms.R; - -import org.microg.gms.gcm.GcmPrefs; -import org.microg.gms.gcm.McsService; -import org.microg.gms.gcm.TriggerReceiver; -import org.microg.tools.ui.ResourceSettingsFragment; - -public class GcmAdvancedFragment extends ResourceSettingsFragment { - - private static String[] HEARTBEAT_PREFS = new String[]{GcmPrefs.PREF_NETWORK_MOBILE, GcmPrefs.PREF_NETWORK_ROAMING, GcmPrefs.PREF_NETWORK_WIFI, GcmPrefs.PREF_NETWORK_OTHER}; - - public GcmAdvancedFragment() { - preferencesResource = R.xml.preferences_gcm_advanced; - } - - @Override - public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) { - super.onCreatePreferences(savedInstanceState, rootKey); - for (String pref : HEARTBEAT_PREFS) { - findPreference(pref).setOnPreferenceChangeListener((preference, newValue) -> { - getPreferenceManager().getSharedPreferences().edit().putString(preference.getKey(), (String) newValue).apply(); - updateContent(); - if (newValue.equals("-1") && preference.getKey().equals(McsService.activeNetworkPref)) { - McsService.stop(getContext()); - } else if (!McsService.isConnected(getContext())) { - getContext().sendBroadcast(new Intent(TriggerReceiver.FORCE_TRY_RECONNECT, null, getContext(), TriggerReceiver.class)); - } - return true; - }); - } - updateContent(); - } - - @Override - public void onResume() { - super.onResume(); - updateContent(); - } - - private void updateContent() { - GcmPrefs prefs = GcmPrefs.get(getContext()); - for (String pref : HEARTBEAT_PREFS) { - Preference preference = findPreference(pref); - int state = prefs.getNetworkValue(pref); - if (state == 0) { - int heartbeat = prefs.getHeartbeatMsFor(preference.getKey(), true); - if (heartbeat == 0) { - preference.setSummary(getString(R.string.service_status_enabled_short) + " / " + getString(R.string.gcm_status_pref_default)); - } else { - preference.setSummary(getString(R.string.service_status_enabled_short) + " / " + getString(R.string.gcm_status_pref_default) + ": " + getHeartbeatString(heartbeat)); - } - } else if (state == -1) { - preference.setSummary(getString(R.string.service_status_disabled_short)); - } else { - preference.setSummary(getString(R.string.service_status_enabled_short) + " / " + getString(R.string.gcm_status_pref_manual) + ": " + getHeartbeatString(state * 60000)); - } - } - } - - private String getHeartbeatString(int heartbeatMs) { - if (heartbeatMs < 120000) { - return (heartbeatMs / 1000) + " " + getString(R.string.gcm_status_pref_sec); - } - return (heartbeatMs / 60000) + " " + getString(R.string.gcm_status_pref_min); - } -} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/chimera/ServiceProvider.kt b/play-services-core/src/main/kotlin/org/microg/gms/chimera/ServiceProvider.kt new file mode 100644 index 00000000..24dfa1c0 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/chimera/ServiceProvider.kt @@ -0,0 +1,84 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.chimera + +import android.content.ContentProvider +import android.content.ContentValues +import android.content.Context +import android.content.Intent +import android.database.Cursor +import android.database.MatrixCursor +import android.net.Uri +import android.os.Bundle +import android.util.Log +import androidx.core.os.bundleOf +import org.microg.gms.DummyService +import org.microg.gms.common.GmsService +import org.microg.gms.common.RemoteListenerProxy + +class ServiceProvider : ContentProvider() { + + override fun onCreate(): Boolean { + Log.d(TAG, "onCreate") + return true + } + + override fun call(method: String, arg: String?, extras: Bundle?): Bundle? { + when (method) { + "serviceIntentCall" -> { + val serviceAction = extras?.getString("serviceActionBundleKey") ?: return null + val ourServiceAction = GmsService.byAction(serviceAction)?.takeIf { it.SERVICE_ID > 0 }?.ACTION ?: serviceAction + val context = context!! + val intent = Intent(ourServiceAction).apply { `package` = context.packageName } + val resolveInfo = context.packageManager.resolveService(intent, 0) + if (resolveInfo != null) { + intent.setClassName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name) + } else { + intent.setClass(context, DummyService::class.java) + } + Log.d(TAG, "$method: $serviceAction -> $intent") + return bundleOf( + "serviceResponseIntentKey" to intent + ) + } + else -> { + Log.d(TAG, "$method: $arg, $extras") + return super.call(method, arg, extras) + } + } + } + + override fun query(uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor? { + val cursor = MatrixCursor(COLUMNS) + Log.d(TAG, "query: $uri") + 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 "vnd.android.cursor.item/com.google.android.gms.chimera" + } + + companion object { + private const val TAG = "ChimeraServiceProvider" + private val COLUMNS = arrayOf("version", "apkPath", "loaderPath", "apkDescStr") + } +} \ No newline at end of file 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 69c84b30..1b0e0c94 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 @@ -57,24 +57,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) { - val accepted: Boolean = suspendCoroutine { continuation -> - val i = Intent(context, AskPushPermission::class.java) - i.putExtra(AskPushPermission.EXTRA_REQUESTED_PACKAGE, packageName) - i.putExtra(AskPushPermission.EXTRA_RESULT_RECEIVER, object : ResultReceiver(null) { - override fun onReceiveResult(resultCode: Int, resultData: Bundle?) { - continuation.resume(resultCode == Activity.RESULT_OK) - } - }) - i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - i.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) - context.startActivity(i) - } - if (!accepted) { - throw RuntimeException("Push permission not granted to app") - } - } else if (app?.allowRegister == false) { + if (app?.allowRegister == false) { throw RuntimeException("Push permission not granted to app") } } 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 576a01f0..b6717ee4 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 @@ -22,23 +22,29 @@ 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) : Serializable +data class ServiceInfo(val configuration: ServiceConfiguration, val connected: Boolean, val startTimestamp: Long, val learntMobileInterval: Int, val learntWifiInterval: Int, val learntOtherInterval: Int) : Serializable // TODO: Intervals -data class ServiceConfiguration(val enabled: Boolean, val confirmNewApps: Boolean) : Serializable { +data class ServiceConfiguration(val enabled: Boolean, val mobile: Int, val wifi: Int, val roaming: Int, val other: Int) : Serializable { fun saveToPrefs(context: Context) { - GcmPrefs.setEnabled(context, enabled) - // TODO: confirm new apps + GcmPrefs.get(context).apply { + isEnabled = enabled + mobileInterval = mobile + wifiInterval = wifi + roamingInterval = roaming + otherInterval = other + } } } -private fun GcmPrefs.toConfiguration(): ServiceConfiguration = ServiceConfiguration(isEnabled, isConfirmNewApps) +private fun GcmPrefs.toConfiguration(): ServiceConfiguration = ServiceConfiguration(isEnabled, mobileInterval, wifiInterval, roamingInterval, otherInterval) class ServiceInfoReceiver : BroadcastReceiver() { private fun sendInfoResponse(context: Context) { context.sendOrderedBroadcast(Intent(ACTION_SERVICE_INFO_RESPONSE).apply { setPackage(context.packageName) - putExtra(EXTRA_SERVICE_INFO, ServiceInfo(GcmPrefs.get(context).toConfiguration(), McsService.isConnected(context), McsService.getStartTimestamp())) + val prefs = GcmPrefs.get(context) + putExtra(EXTRA_SERVICE_INFO, ServiceInfo(prefs.toConfiguration(), McsService.isConnected(context), McsService.getStartTimestamp(), prefs.learntMobileInterval, prefs.learntWifiInterval, prefs.learntOtherInterval)) }, null) } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/provision/ProvisionService.kt b/play-services-core/src/main/kotlin/org/microg/gms/provision/ProvisionService.kt index e454bde3..c690a24a 100755 --- a/play-services-core/src/main/kotlin/org/microg/gms/provision/ProvisionService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/provision/ProvisionService.kt @@ -14,6 +14,8 @@ import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.delay import org.microg.gms.checkin.CheckinPrefs import org.microg.gms.gcm.GcmPrefs +import org.microg.gms.gcm.getGcmServiceInfo +import org.microg.gms.gcm.setGcmServiceConfiguration class ProvisionService : LifecycleService() { private fun Bundle.getBooleanOrNull(key: String): Boolean? { @@ -29,7 +31,7 @@ class ProvisionService : LifecycleService() { } intent?.extras?.getBooleanOrNull("checkin_enabled")?.let { CheckinPrefs.setEnabled(this@ProvisionService, it) } - intent?.extras?.getBooleanOrNull("gcm_enabled")?.let { GcmPrefs.setEnabled(this@ProvisionService, it) } + intent?.extras?.getBooleanOrNull("gcm_enabled")?.let { setGcmServiceConfiguration(this@ProvisionService, getGcmServiceInfo(this@ProvisionService).configuration.copy(enabled = it)) } // What else? delay(2 * 1000) // Wait 2 seconds to give provisioning some extra time diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAdvancedFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAdvancedFragment.kt new file mode 100644 index 00000000..c19374fe --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationAdvancedFragment.kt @@ -0,0 +1,104 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ +package org.microg.gms.ui + +import android.os.Bundle +import androidx.lifecycle.lifecycleScope +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.TwoStatePreference +import com.mgoogle.android.gms.R +import org.microg.gms.gcm.* + +class PushNotificationAdvancedFragment : PreferenceFragmentCompat() { + private lateinit var networkMobile: ListPreference + private lateinit var networkWifi: ListPreference + private lateinit var networkRoaming: ListPreference + private lateinit var networkOther: ListPreference + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.preferences_gcm_advanced) + } + + override fun onBindPreferences() { + networkMobile = preferenceScreen.findPreference(GcmPrefs.PREF_NETWORK_MOBILE) ?: networkMobile + networkWifi = preferenceScreen.findPreference(GcmPrefs.PREF_NETWORK_WIFI) ?: networkWifi + networkRoaming = preferenceScreen.findPreference(GcmPrefs.PREF_NETWORK_ROAMING) ?: networkRoaming + networkOther = preferenceScreen.findPreference(GcmPrefs.PREF_NETWORK_OTHER) ?: networkOther + + networkMobile.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + lifecycleScope.launchWhenResumed { + (newValue as? String)?.toIntOrNull()?.let { + setGcmServiceConfiguration(requireContext(), getGcmServiceInfo(requireContext()).configuration.copy(mobile = it)) + } + updateContent() + } + true + } + networkWifi.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + lifecycleScope.launchWhenResumed { + (newValue as? String)?.toIntOrNull()?.let { + setGcmServiceConfiguration(requireContext(), getGcmServiceInfo(requireContext()).configuration.copy(wifi = it)) + } + updateContent() + } + true + } + networkRoaming.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + lifecycleScope.launchWhenResumed { + (newValue as? String)?.toIntOrNull()?.let { + setGcmServiceConfiguration(requireContext(), getGcmServiceInfo(requireContext()).configuration.copy(roaming = it)) + } + updateContent() + } + true + } + networkOther.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + lifecycleScope.launchWhenResumed { + (newValue as? String)?.toIntOrNull()?.let { + setGcmServiceConfiguration(requireContext(), getGcmServiceInfo(requireContext()).configuration.copy(other = it)) + } + updateContent() + } + true + } + } + + override fun onResume() { + super.onResume() + updateContent() + } + + private fun updateContent() { + lifecycleScope.launchWhenResumed { + val serviceInfo = getGcmServiceInfo(requireContext()) + networkMobile.value = serviceInfo.configuration.mobile.toString() + networkMobile.summary = getSummaryString(serviceInfo.configuration.mobile, serviceInfo.learntMobileInterval) + networkWifi.value = serviceInfo.configuration.wifi.toString() + networkWifi.summary = getSummaryString(serviceInfo.configuration.wifi, serviceInfo.learntWifiInterval) + networkRoaming.value = serviceInfo.configuration.roaming.toString() + networkRoaming.summary = getSummaryString(serviceInfo.configuration.roaming, serviceInfo.learntMobileInterval) + networkOther.value = serviceInfo.configuration.other.toString() + networkOther.summary = getSummaryString(serviceInfo.configuration.other, serviceInfo.learntOtherInterval) + } + } + + private fun getSummaryString(value: Int, learnt: Int): String = when (value) { + -1 -> getString(R.string.service_status_disabled_short) + 0 -> getString(R.string.service_status_enabled_short) + " / " + getString(R.string.gcm_status_pref_default) + ": " + getHeartbeatString(learnt) + else -> getString(R.string.service_status_enabled_short) + " / " + getString(R.string.gcm_status_pref_manual) + ": " + getHeartbeatString(value * 60000) + } + + private fun getHeartbeatString(heartbeatMs: Int): String { + return if (heartbeatMs < 120000) { + (heartbeatMs / 1000).toString() + " " + getString(R.string.gcm_status_pref_sec) + } else (heartbeatMs / 60000).toString() + " " + getString(R.string.gcm_status_pref_min) + } + + companion object { + private val HEARTBEAT_PREFS = arrayOf(GcmPrefs.PREF_NETWORK_MOBILE, GcmPrefs.PREF_NETWORK_ROAMING, GcmPrefs.PREF_NETWORK_WIFI, GcmPrefs.PREF_NETWORK_OTHER) + } +} \ No newline at end of file diff --git a/play-services-core/src/main/res/navigation/nav_settings.xml b/play-services-core/src/main/res/navigation/nav_settings.xml index 1ada352c..fb1cfa00 100755 --- a/play-services-core/src/main/res/navigation/nav_settings.xml +++ b/play-services-core/src/main/res/navigation/nav_settings.xml @@ -52,7 +52,7 @@ - @string/service_status_disabled - @string/service_status_default - Intervalo de ping: 2 minutos - Intervalo de ping: 5 minutos - Intervalo de ping: 10 minutos - Intervalo de ping: 15 minutos - Intervalo de ping: 20 minutos - Intervalo de ping: 30 minutos + @string/service_status_disabled_short + @string/gcm_status_pref_default + Intervalo de ping: 2 minutos + Intervalo de ping: 5 minutos + Intervalo de ping: 10 minutos + Intervalo de ping: 15 minutos + Intervalo de ping: 20 minutos + Intervalo de ping: 30 minutos \ No newline at end of file diff --git a/play-services-core/src/main/res/values-es/strings.xml b/play-services-core/src/main/res/values-es/strings.xml index 21e6614f..3e25d84e 100644 --- a/play-services-core/src/main/res/values-es/strings.xml +++ b/play-services-core/src/main/res/values-es/strings.xml @@ -59,10 +59,8 @@ Esto puede tardar unos minutos." Acceso extendido a los servicios de Google Registro de dispositivos Google - Google Cloud Messaging + Cloud Messaging - Deshabilitado - Por Defecto Encendido Apagado @@ -85,7 +83,7 @@ Esto puede tardar unos minutos." Ultimo registro: %1$s Optimizaciones de bateria habilitadas - Has habilitado Google Cloud Messaging pero tienes las optimizacion de bateria activada para los servicios de microG. Para que lleguen las notificaciones deberás deshabilitar la optimización de batería para microG. + Has habilitado Cloud Messaging pero tienes las optimizacion de bateria activada para los servicios de microG. Para que lleguen las notificaciones deberás deshabilitar la optimización de batería para microG. Deshabilitar optimizaciones Preferencias de Cuenta @@ -100,7 +98,7 @@ Esto puede tardar unos minutos." Cuenta Añadir cuenta de Google Recibir notificaciones push - Google Cloud Messaging es un proveedor de notificaciónes push usado por muchas aplicaciones de terceros. Pará usarlo tienes que activar registro de dispositivos. + Cloud Messaging es un proveedor de notificaciónes push usado por muchas aplicaciones de terceros. Pará usarlo tienes que activar registro de dispositivos. Acerca de Vanced microG Solucion para Cast duplicado diff --git a/play-services-core/src/main/res/values-in/arrays.xml b/play-services-core/src/main/res/values-in/arrays.xml index c4cfa81e..c9b0c23b 100644 --- a/play-services-core/src/main/res/values-in/arrays.xml +++ b/play-services-core/src/main/res/values-in/arrays.xml @@ -18,8 +18,8 @@ - @string/service_status_disabled - @string/service_status_default + @string/service_status_disabled_short + @string/gcm_status_pref_default Ping interval: 2 menit Ping interval: 5 menit Ping interval: 10 menit diff --git a/play-services-core/src/main/res/values-in/strings.xml b/play-services-core/src/main/res/values-in/strings.xml index 2c3d2d34..238d2df7 100644 --- a/play-services-core/src/main/res/values-in/strings.xml +++ b/play-services-core/src/main/res/values-in/strings.xml @@ -59,10 +59,8 @@ Ini bisa berlangsung beberapa menit." Akses lebih ke layanan Google Google device registration - Google Cloud Messaging + Cloud Messaging - Dinonaktifkan - Default Hidup Mati @@ -85,7 +83,7 @@ Ini bisa berlangsung beberapa menit." Registrasi terakhir: %1$s Optimisasi baterai diaktifkan - Anda mengaktifkan Google Cloud Messaging namun mengaktifkan optimisasi baterai untuk layanan utama microG. Untuk mendapatkan notifikasi push anda harus menonaktifkan optimisasi baterai. + Anda mengaktifkan Cloud Messaging namun mengaktifkan optimisasi baterai untuk layanan utama microG. Untuk mendapatkan notifikasi push anda harus menonaktifkan optimisasi baterai. Nonaktifkan optimisasi Preferensi akun @@ -100,7 +98,7 @@ Ini bisa berlangsung beberapa menit." Akun Tambahkan akun Google Terima notifikasi push - Google Cloud Messaging adalah penyedia notifikasi push yang digunakan pada banyak aplikasi pihak ketiga. Untuk menggunakannya anda harus mengaktifkan device registration. + Cloud Messaging adalah penyedia notifikasi push yang digunakan pada banyak aplikasi pihak ketiga. Untuk menggunakannya anda harus mengaktifkan device registration. Tentang Vanced microG Perbaikan Cast terduplikasi diff --git a/play-services-core/src/main/res/values-it/arrays.xml b/play-services-core/src/main/res/values-it/arrays.xml index 6326659b..d6c19683 100644 --- a/play-services-core/src/main/res/values-it/arrays.xml +++ b/play-services-core/src/main/res/values-it/arrays.xml @@ -18,8 +18,8 @@ - @string/service_status_disabled - @string/service_status_default + @string/service_status_disabled_short + @string/gcm_status_pref_default Intervallo ping: 2 minuti Intervallo ping: 5 minuti Intervallo ping: 10 minuti diff --git a/play-services-core/src/main/res/values-it/strings.xml b/play-services-core/src/main/res/values-it/strings.xml index 26b045f0..1a6facfa 100755 --- a/play-services-core/src/main/res/values-it/strings.xml +++ b/play-services-core/src/main/res/values-it/strings.xml @@ -59,10 +59,8 @@ Questo potrà richiedere un paio di minuti" Estendi accesso ai servizi Google Registrazione dispositivo Google - Messaggistica Cloud Google + Messaggistica Cloud - Disattivata - Predefinito Attiva Disattivata @@ -85,7 +83,7 @@ Questo potrà richiedere un paio di minuti" Ultima registrazione: %1$s Ottimizzazione batteria attivata - Hai attivato l\'opzione Messaggistica Cloud Google ma i Servizi Vanced microG risultano al momento limitati dall\'ottimizzazione energetica di sistema. Se desideri ricevere le notifiche push, escludi i microG da questa ottimizzazione. + Hai attivato l\'opzione Messaggistica Cloud ma i Servizi Vanced microG risultano al momento limitati dall\'ottimizzazione energetica di sistema. Se desideri ricevere le notifiche push, escludi i microG da questa ottimizzazione. Disattiva ottimizzazione Preferenze account @@ -100,7 +98,7 @@ Questo potrà richiedere un paio di minuti" Account Aggiungi account Google Ricevi notifiche push - Messaggistica Cloud Google è un fornitore di notifiche push presente in molte applicazioni di terze parti. Per utilizzarlo è necessario attivare la registrazione del dispositivo. + Messaggistica Cloud è un fornitore di notifiche push presente in molte applicazioni di terze parti. Per utilizzarlo è necessario attivare la registrazione del dispositivo. Informazioni su Vanced microG Correzione cast duplicato diff --git a/play-services-core/src/main/res/values-ru/arrays.xml b/play-services-core/src/main/res/values-ru/arrays.xml index 393425e0..51719566 100644 --- a/play-services-core/src/main/res/values-ru/arrays.xml +++ b/play-services-core/src/main/res/values-ru/arrays.xml @@ -18,8 +18,8 @@ - @string/service_status_disabled - @string/service_status_default + @string/service_status_disabled_short + @string/gcm_status_pref_default Интервал пинга: 2 минуты Интервал пинга: 5 минут Интервал пинга: 10 минут diff --git a/play-services-core/src/main/res/values-ru/strings.xml b/play-services-core/src/main/res/values-ru/strings.xml index 9ddbec51..4bb315e6 100644 --- a/play-services-core/src/main/res/values-ru/strings.xml +++ b/play-services-core/src/main/res/values-ru/strings.xml @@ -59,10 +59,8 @@ Расширенный доступ к сервисам Google Регистрация устройства в Google - Google Cloud Messaging + Cloud Messaging - Отключен - По умолчанию Вкл Выкл @@ -85,7 +83,7 @@ Последняя регистрация: %1$s Включена экономия заряда батареи - Вы включили Google Cloud Messaging, но не отключили экономию заряда батареи для Vanced microG. Для корректной работы уведомлений вам нужно отключить экономию заряда батареи. + Вы включили Cloud Messaging, но не отключили экономию заряда батареи для Vanced microG. Для корректной работы уведомлений вам нужно отключить экономию заряда батареи. Отключить экономию Настройки аккаунта @@ -100,7 +98,7 @@ Аккаунт Добавить аккаунт Google Получать push-уведомления - Google Cloud Messaging позволяет получать уведомления от многих приложений. Чтобы использовать GCM, включите регистрацию устройства в Google. + Cloud Messaging позволяет получать уведомления от многих приложений. Чтобы использовать GCM, включите регистрацию устройства в Google. О Vanced microG Исправление двух кнопок трансляции diff --git a/play-services-core/src/main/res/values/arrays.xml b/play-services-core/src/main/res/values/arrays.xml index cac5386e..71518aec 100755 --- a/play-services-core/src/main/res/values/arrays.xml +++ b/play-services-core/src/main/res/values/arrays.xml @@ -29,8 +29,8 @@ - @string/service_status_disabled - @string/service_status_default + @string/service_status_disabled_short + @string/gcm_status_pref_default Ping interval: 2 minutes Ping interval: 5 minutes Ping interval: 10 minutes diff --git a/play-services-core/src/main/res/values/strings.xml b/play-services-core/src/main/res/values/strings.xml index d985ae01..a0d50745 100755 --- a/play-services-core/src/main/res/values/strings.xml +++ b/play-services-core/src/main/res/values/strings.xml @@ -59,10 +59,8 @@ This can take a couple of minutes." Extended access to Google services Google device registration - Google Cloud Messaging + Cloud Messaging - Disabled - Default On Off @@ -85,7 +83,7 @@ This can take a couple of minutes." Last registration: %1$s Battery optimizations enabled - You enabled Google Cloud Messaging but have battery optimizations active for microG Services Core. For push notifications to arrive you should disable battery optimizations. + You enabled Cloud Messaging but have battery optimizations active for microG Services Core. For push notifications to arrive you should disable battery optimizations. Disable optimization Account preferences @@ -100,7 +98,7 @@ This can take a couple of minutes." Account Add Google account Receive push notifications - Google Cloud Messaging is a push notification provider used by many third-party applications. To use it you must enable device registration. + Cloud Messaging is a push notification provider used by many third-party applications. To use it you must enable device registration. About Vanced microG Cast duplication fix