diff --git a/play-services-core/src/main/AndroidManifest.xml b/play-services-core/src/main/AndroidManifest.xml index 831a1514..d2305954 100644 --- a/play-services-core/src/main/AndroidManifest.xml +++ b/play-services-core/src/main/AndroidManifest.xml @@ -193,6 +193,8 @@ + + @@ -238,7 +240,7 @@ - + @@ -627,6 +629,8 @@ + + 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 f090c97e..348f4244 100644 --- 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 @@ -9,6 +9,11 @@ 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"; @@ -16,6 +21,9 @@ 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()); + } if (context == null) return new CheckinPrefs(null); INSTANCE = new CheckinPrefs(context.getApplicationContext()); } @@ -23,18 +31,30 @@ public class CheckinPrefs implements SharedPreferences.OnSharedPreferenceChangeL } 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 = preferences.getBoolean(PREF_ENABLE_CHECKIN, false); + checkinEnabled = getSettingsBoolean(PREF_ENABLE_CHECKIN, false); } @Override 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 index 4cdfd88c..30e0a1af 100644 --- 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 @@ -55,6 +55,6 @@ public class LastCheckinInfo { .putLong(PREF_SECURITY_TOKEN, securityToken) .putString(PREF_VERSION_INFO, versionInfo) .putString(PREF_DEVICE_DATA_VERSION_INFO, deviceDataVersionInfo) - .apply(); + .commit(); } } diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/GcmDatabase.java b/play-services-core/src/main/java/org/microg/gms/gcm/GcmDatabase.java index 3dd67b53..bc524047 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/GcmDatabase.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/GcmDatabase.java @@ -21,6 +21,7 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; +import android.os.Build; import android.text.TextUtils; import java.util.ArrayList; @@ -65,6 +66,9 @@ public class GcmDatabase extends SQLiteOpenHelper { public GcmDatabase(Context context) { super(context, DB_NAME, null, DB_VERSION); this.context = context; + if (Build.VERSION.SDK_INT >= 16) { + this.setWriteAheadLoggingEnabled(true); + } } public static class App { 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 4bfe71d5..568efd1f 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 @@ -24,6 +24,9 @@ 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; @@ -50,6 +53,9 @@ 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); INSTANCE = new GcmPrefs(context.getApplicationContext()); } @@ -70,30 +76,43 @@ public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListe private int learntMobile = 300000; private int learntOther = 300000; - private SharedPreferences defaultPreferences; + private SharedPreferences preferences; + private SharedPreferences systemDefaultPreferences; private GcmPrefs(Context context) { if (context != null) { - defaultPreferences = PreferenceManager.getDefaultSharedPreferences(context); - defaultPreferences.registerOnSharedPreferenceChangeListener(this); + 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() { - gcmLogEnabled = defaultPreferences.getBoolean(PREF_FULL_LOG, true); - lastPersistedId = defaultPreferences.getString(PREF_LAST_PERSISTENT_ID, ""); - confirmNewApps = defaultPreferences.getBoolean(PREF_CONFIRM_NEW_APPS, false); - gcmEnabled = defaultPreferences.getBoolean(PREF_ENABLE_GCM, false); + gcmEnabled = getSettingsBoolean(PREF_ENABLE_GCM, false); + gcmLogEnabled = getSettingsBoolean(PREF_FULL_LOG, true); + confirmNewApps = getSettingsBoolean(PREF_CONFIRM_NEW_APPS, false); - networkMobile = Integer.parseInt(defaultPreferences.getString(PREF_NETWORK_MOBILE, "0")); - networkWifi = Integer.parseInt(defaultPreferences.getString(PREF_NETWORK_WIFI, "0")); - networkRoaming = Integer.parseInt(defaultPreferences.getString(PREF_NETWORK_ROAMING, "0")); - networkOther = Integer.parseInt(defaultPreferences.getString(PREF_NETWORK_OTHER, "0")); + lastPersistedId = preferences.getString(PREF_LAST_PERSISTENT_ID, ""); - learntMobile = defaultPreferences.getInt(PREF_LEARNT_MOBILE, 300000); - learntWifi = defaultPreferences.getInt(PREF_LEARNT_WIFI, 300000); - learntOther = defaultPreferences.getInt(PREF_LEARNT_OTHER, 300000); + 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) { @@ -182,7 +201,7 @@ public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListe 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)); - defaultPreferences.edit().putInt(PREF_LEARNT_MOBILE, learntMobile).putInt(PREF_LEARNT_WIFI, learntWifi).putInt(PREF_LEARNT_OTHER, learntOther).apply(); + preferences.edit().putInt(PREF_LEARNT_MOBILE, learntMobile).putInt(PREF_LEARNT_WIFI, learntWifi).putInt(PREF_LEARNT_OTHER, learntOther).apply(); } @Override @@ -223,11 +242,11 @@ public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListe public void extendLastPersistedId(String id) { if (!lastPersistedId.isEmpty()) lastPersistedId += "|"; lastPersistedId += id; - defaultPreferences.edit().putString(PREF_LAST_PERSISTENT_ID, lastPersistedId).apply(); + preferences.edit().putString(PREF_LAST_PERSISTENT_ID, lastPersistedId).apply(); } public void clearLastPersistedId() { lastPersistedId = ""; - defaultPreferences.edit().putString(PREF_LAST_PERSISTENT_ID, lastPersistedId).apply(); + 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 32a91736..03dc0d97 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 @@ -176,8 +176,8 @@ public class McsService extends Service implements Handler.Callback { } } - private static void logd(String msg) { - if (GcmPrefs.get(null).isGcmLogEnabled()) Log.d(TAG, msg); + private static void logd(Context context, String msg) { + if (context == null || GcmPrefs.get(context).isGcmLogEnabled()) Log.d(TAG, msg); } @Override @@ -237,7 +237,7 @@ public class McsService extends Service implements Handler.Callback { public synchronized static boolean isConnected() { if (inputStream == null || !inputStream.isAlive() || outputStream == null || !outputStream.isAlive()) { - logd("Connection is not enabled or dead."); + logd(null, "Connection is not enabled or dead."); return false; } // consider connection to be dead if we did not receive an ack within twice the heartbeat interval @@ -245,7 +245,7 @@ public class McsService extends Service implements Handler.Callback { if (heartbeatMs < 0) { closeAll(); } else if (SystemClock.elapsedRealtime() - lastHeartbeatAckElapsedRealtime > 2 * heartbeatMs) { - logd("No heartbeat for " + (SystemClock.elapsedRealtime() - lastHeartbeatAckElapsedRealtime) / 1000 + " seconds, connection assumed to be dead after " + 2 * heartbeatMs / 1000 + " seconds"); + logd(null, "No heartbeat for " + (SystemClock.elapsedRealtime() - lastHeartbeatAckElapsedRealtime) / 1000 + " seconds, connection assumed to be dead after " + 2 * heartbeatMs / 1000 + " seconds"); GcmPrefs.get(null).learnTimeout(activeNetworkPref); return false; } @@ -259,7 +259,7 @@ public class McsService extends Service implements Handler.Callback { public static void scheduleReconnect(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE); long delay = getCurrentDelay(); - logd("Scheduling reconnect in " + delay / 1000 + " seconds..."); + logd(context, "Scheduling reconnect in " + delay / 1000 + " seconds..."); PendingIntent pi = PendingIntent.getBroadcast(context, 1, new Intent(ACTION_RECONNECT, null, context, TriggerReceiver.class), 0); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delay, pi); @@ -275,7 +275,7 @@ public class McsService extends Service implements Handler.Callback { if (heartbeatMs < 0) { closeAll(); } - logd("Scheduling heartbeat in " + heartbeatMs / 1000 + " seconds..."); + logd(context, "Scheduling heartbeat in " + heartbeatMs / 1000 + " seconds..."); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // This is supposed to work even when running in idle and without battery optimization disabled alarmManager.setExactAndAllowWhileIdle(ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + heartbeatMs, heartbeatIntent); @@ -449,11 +449,11 @@ public class McsService extends Service implements Handler.Callback { return; } - logd("Starting MCS connection..."); + logd(this, "Starting MCS connection..."); Socket socket = new Socket(SERVICE_HOST, SERVICE_PORT); - logd("Connected to " + SERVICE_HOST + ":" + SERVICE_PORT); + logd(this, "Connected to " + SERVICE_HOST + ":" + SERVICE_PORT); sslSocket = SSLContext.getDefault().getSocketFactory().createSocket(socket, SERVICE_HOST, SERVICE_PORT, true); - logd("Activated SSL with " + SERVICE_HOST + ":" + SERVICE_PORT); + logd(this, "Activated SSL with " + SERVICE_HOST + ":" + SERVICE_PORT); inputStream = new McsInputStream(sslSocket.getInputStream(), rootHandler); outputStream = new McsOutputStream(sslSocket.getOutputStream(), rootHandler); inputStream.start(); @@ -476,7 +476,7 @@ public class McsService extends Service implements Handler.Callback { private void handleLoginResponse(LoginResponse loginResponse) { if (loginResponse.error == null) { GcmPrefs.get(this).clearLastPersistedId(); - logd("Logged in"); + logd(this, "Logged in"); wakeLock.release(); } else { throw new RuntimeException("Could not login: " + loginResponse.error); @@ -561,13 +561,13 @@ public class McsService extends Service implements Handler.Callback { if (receiverPermission == null) { // Without receiver permission, we only restrict by package name - logd("Deliver message to all receivers in package " + packageName); + logd(this, "Deliver message to all receivers in package " + packageName); intent.setPackage(packageName); sendOrderedBroadcast(intent, null); } else { List infos = getPackageManager().queryBroadcastReceivers(intent, PackageManager.GET_RESOLVED_FILTER); if (infos == null || infos.isEmpty()) { - logd("No target for message, wut?"); + logd(this, "No target for message, wut?"); } else { for (ResolveInfo resolveInfo : infos) { Intent targetIntent = new Intent(intent); @@ -578,7 +578,7 @@ public class McsService extends Service implements Handler.Callback { try { if (getUserIdMethod != null && addPowerSaveTempWhitelistAppMethod != null && deviceIdleController != null) { int userId = (int) getUserIdMethod.invoke(null, getPackageManager().getApplicationInfo(packageName, 0).uid); - logd("Adding app " + packageName + " for userId " + userId + " to the temp whitelist"); + logd(this, "Adding app " + packageName + " for userId " + userId + " to the temp whitelist"); addPowerSaveTempWhitelistAppMethod.invoke(deviceIdleController, packageName, 10000, userId, "GCM Push"); } } catch (Exception e) { @@ -586,11 +586,11 @@ public class McsService extends Service implements Handler.Callback { } } // We don't need receiver permission for our own package - logd("Deliver message to own receiver " + resolveInfo); + logd(this, "Deliver message to own receiver " + resolveInfo); sendOrderedBroadcast(targetIntent, null); } else if (resolveInfo.filter.hasCategory(packageName)) { // Permission required - logd("Deliver message to third-party receiver (with permission check)" + resolveInfo); + logd(this, "Deliver message to third-party receiver (with permission check)" + resolveInfo); sendOrderedBroadcast(targetIntent, receiverPermission); } } @@ -640,21 +640,21 @@ public class McsService extends Service implements Handler.Callback { return true; case MSG_INPUT_ERROR: case MSG_OUTPUT_ERROR: - logd("I/O error: " + msg.obj); + logd(this, "I/O error: " + msg.obj); rootHandler.sendMessage(rootHandler.obtainMessage(MSG_TEARDOWN, msg.obj)); return true; case MSG_TEARDOWN: - logd("Teardown initiated, reason: " + msg.obj); + logd(this, "Teardown initiated, reason: " + msg.obj); handleTeardown(msg); return true; case MSG_CONNECT: - logd("Connect initiated, reason: " + msg.obj); + logd(this, "Connect initiated, reason: " + msg.obj); if (!isConnected()) { connect(); } return true; case MSG_HEARTBEAT: - logd("Heartbeat initiated, reason: " + msg.obj); + logd(this, "Heartbeat initiated, reason: " + msg.obj); if (isConnected()) { HeartbeatPing.Builder ping = new HeartbeatPing.Builder(); if (inputStream.newStreamIdAvailable()) { @@ -663,12 +663,12 @@ public class McsService extends Service implements Handler.Callback { send(MCS_HEARTBEAT_PING_TAG, ping.build()); scheduleHeartbeat(this); } else { - logd("Ignoring heartbeat, not connected!"); + logd(this, "Ignoring heartbeat, not connected!"); scheduleReconnect(this); } return true; case MSG_ACK: - logd("Ack initiated, reason: " + msg.obj); + logd(this, "Ack initiated, reason: " + msg.obj); if (isConnected()) { IqStanza.Builder iq = new IqStanza.Builder() .type(IqStanza.IqType.SET) @@ -680,11 +680,11 @@ public class McsService extends Service implements Handler.Callback { } send(MCS_IQ_STANZA_TAG, iq.build()); } else { - logd("Ignoring ack, not connected!"); + logd(this, "Ignoring ack, not connected!"); } return true; case MSG_OUTPUT_READY: - logd("Sending login request..."); + logd(this, "Sending login request..."); send(MCS_LOGIN_REQUEST_TAG, buildLoginRequest()); return true; case MSG_OUTPUT_DONE: 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 3bc5e9a5..1166f385 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 @@ -45,7 +45,7 @@ public class TriggerReceiver extends WakefulBroadcastReceiver { public synchronized static void register(Context context) { if (SDK_INT >= N && !registered) { IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"); - context.registerReceiver(new TriggerReceiver(), intentFilter); + context.getApplicationContext().registerReceiver(new TriggerReceiver(), intentFilter); registered = true; } } diff --git a/play-services-core/src/main/java/org/microg/gms/snet/SafetyNetPrefs.java b/play-services-core/src/main/java/org/microg/gms/snet/SafetyNetPrefs.java index a6475791..e3c11a89 100644 --- a/play-services-core/src/main/java/org/microg/gms/snet/SafetyNetPrefs.java +++ b/play-services-core/src/main/java/org/microg/gms/snet/SafetyNetPrefs.java @@ -19,6 +19,11 @@ package org.microg.gms.snet; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; +import android.util.Log; + +import org.microg.gms.common.PackageUtils; + +import java.io.File; public class SafetyNetPrefs implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String OFFICIAL_ATTEST_BASE_URL = "https://www.googleapis.com/androidcheck/v1/attestations/attest"; @@ -33,6 +38,9 @@ public class SafetyNetPrefs implements SharedPreferences.OnSharedPreferenceChang public static SafetyNetPrefs get(Context context) { if (INSTANCE == null) { + if (!context.getPackageName().equals(PackageUtils.getProcessName())) { + Log.w("Preferences", SafetyNetPrefs.class.getName() + " initialized outside main process", new RuntimeException()); + } if (context == null) return new SafetyNetPrefs(null); INSTANCE = new SafetyNetPrefs(context.getApplicationContext()); } @@ -45,22 +53,41 @@ public class SafetyNetPrefs implements SharedPreferences.OnSharedPreferenceChang private boolean thirdParty; private String customUrl; - private SharedPreferences defaultPreferences; + private SharedPreferences preferences; + private SharedPreferences systemDefaultPreferences; private SafetyNetPrefs(Context context) { if (context != null) { - defaultPreferences = PreferenceManager.getDefaultSharedPreferences(context); - defaultPreferences.registerOnSharedPreferenceChangeListener(this); + 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 String getSettingsString(String key, String def) { + if (systemDefaultPreferences != null) { + def = systemDefaultPreferences.getString(key, def); + } + return preferences.getString(key, def); + } + public void update() { - disabled = defaultPreferences.getBoolean(PREF_SNET_DISABLED, true); - official = defaultPreferences.getBoolean(PREF_SNET_OFFICIAL, false); - selfSigned = defaultPreferences.getBoolean(PREF_SNET_SELF_SIGNED, false); - thirdParty = defaultPreferences.getBoolean(PREF_SNET_THIRD_PARTY, false); - customUrl = defaultPreferences.getString(PREF_SNET_CUSTOM_URL, null); + disabled = getSettingsBoolean(PREF_SNET_DISABLED, true); + official = getSettingsBoolean(PREF_SNET_OFFICIAL, false); + selfSigned = getSettingsBoolean(PREF_SNET_SELF_SIGNED, false); + thirdParty = getSettingsBoolean(PREF_SNET_THIRD_PARTY, false); + customUrl = getSettingsString(PREF_SNET_CUSTOM_URL, null); } @Override @@ -73,11 +100,13 @@ public class SafetyNetPrefs implements SharedPreferences.OnSharedPreferenceChang } public void setEnabled(boolean enabled) { - defaultPreferences.edit().putBoolean(PREF_SNET_DISABLED, !enabled).apply(); + SharedPreferences.Editor edit = preferences.edit(); + edit.putBoolean(PREF_SNET_DISABLED, !enabled); if (enabled && !isEnabled()) { official = true; - defaultPreferences.edit().putBoolean(PREF_SNET_OFFICIAL, true).apply(); + edit.putBoolean(PREF_SNET_OFFICIAL, true); } + edit.commit(); } public boolean isSelfSigned() { diff --git a/play-services-core/src/main/java/org/microg/gms/ui/SettingsFragment.java b/play-services-core/src/main/java/org/microg/gms/ui/SettingsFragment.java deleted file mode 100644 index c0e37661..00000000 --- a/play-services-core/src/main/java/org/microg/gms/ui/SettingsFragment.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.microg.gms.ui; - -import android.os.Build; -import android.os.Bundle; - -import androidx.annotation.Nullable; -import androidx.navigation.NavOptions; -import androidx.navigation.fragment.NavHostFragment; - -import com.google.android.gms.R; - -import org.microg.gms.checkin.CheckinPrefs; -import org.microg.gms.gcm.GcmDatabase; -import org.microg.gms.gcm.GcmPrefs; -import org.microg.gms.nearby.exposurenotification.ExposurePreferences; -import org.microg.gms.snet.SafetyNetPrefs; -import org.microg.tools.ui.ResourceSettingsFragment; - -public class SettingsFragment extends ResourceSettingsFragment { - - public static final String PREF_ABOUT = "pref_about"; - public static final String PREF_GCM = "pref_gcm"; - public static final String PREF_SNET = "pref_snet"; - public static final String PREF_UNIFIEDNLP = "pref_unifiednlp"; - public static final String PREF_CHECKIN = "pref_checkin"; - public static final String PREF_EXPOSURE = "pref_exposure"; - - public SettingsFragment() { - preferencesResource = R.xml.preferences_start; - } - - @Override - public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) { - super.onCreatePreferences(savedInstanceState, rootKey); - updateDetails(); - } - - @Override - public void onResume() { - super.onResume(); - updateDetails(); - } - - private void updateDetails() { - findPreference(PREF_ABOUT).setSummary(getString(R.string.about_version_str, AboutFragment.getSelfVersion(getContext()))); - findPreference(PREF_ABOUT).setOnPreferenceClickListener(preference -> { - UtilsKt.navigate(NavHostFragment.findNavController(SettingsFragment.this), getContext(), R.id.openAbout, null); - return true; - }); - if (GcmPrefs.get(getContext()).isEnabled()) { - GcmDatabase database = new GcmDatabase(getContext()); - int regCount = database.getRegistrationList().size(); - database.close(); - findPreference(PREF_GCM).setSummary(getString(R.string.service_status_enabled_short) + " - " + getResources().getQuantityString(R.plurals.gcm_registered_apps_counter, regCount, regCount)); - } else { - findPreference(PREF_GCM).setSummary(R.string.service_status_disabled_short); - } - findPreference(PREF_GCM).setOnPreferenceClickListener(preference -> { - UtilsKt.navigate(NavHostFragment.findNavController(SettingsFragment.this), getContext(), R.id.openGcmSettings, null); - return true; - }); - - if (SafetyNetPrefs.get(getContext()).isEnabled()) { - String snet_info = ""; - - if (SafetyNetPrefs.get(getContext()).isOfficial()) { - snet_info = getString(R.string.pref_snet_status_official_info); - } else if (SafetyNetPrefs.get(getContext()).isSelfSigned()) { - snet_info = getString(R.string.pref_snet_status_self_signed_info); - } else if (SafetyNetPrefs.get(getContext()).isThirdParty()) { - snet_info = getString(R.string.pref_snet_status_third_party_info); - } - - findPreference(PREF_SNET).setSummary(getString(R.string.service_status_enabled_short)); - } else { - findPreference(PREF_SNET).setSummary(R.string.service_status_disabled_short); - } - findPreference(PREF_SNET).setOnPreferenceClickListener(preference -> { - UtilsKt.navigate(NavHostFragment.findNavController(SettingsFragment.this), getContext(), R.id.openSafetyNetSettings, null); - return true; - }); - -// Preferences unifiedNlPrefs = new Preferences(getContext()); -// int backendCount = TextUtils.isEmpty(unifiedNlPrefs.getLocationBackends()) ? 0 : -// Preferences.splitBackendString(unifiedNlPrefs.getLocationBackends()).length; -// backendCount += TextUtils.isEmpty(unifiedNlPrefs.getGeocoderBackends()) ? 0 : -// Preferences.splitBackendString(unifiedNlPrefs.getGeocoderBackends()).length; -// findPreference(PREF_UNIFIEDNLP).setSummary(getResources().getQuantityString(R.plurals.pref_unifiednlp_summary, backendCount, backendCount)); - findPreference(PREF_UNIFIEDNLP).setOnPreferenceClickListener(preference -> { - UtilsKt.navigate(NavHostFragment.findNavController(SettingsFragment.this), getContext(), R.id.openUnifiedNlpSettings, null); - return true; - }); - if (Build.VERSION.SDK_INT >= 21) { - findPreference(PREF_EXPOSURE).setVisible(true); - if (new ExposurePreferences(getContext()).getScannerEnabled()) { - findPreference(PREF_EXPOSURE).setSummary(getString(R.string.service_status_enabled_short)); - } else { - findPreference(PREF_EXPOSURE).setSummary(R.string.service_status_disabled_short); - } - findPreference(PREF_EXPOSURE).setOnPreferenceClickListener(preference -> { - UtilsKt.navigate(NavHostFragment.findNavController(SettingsFragment.this), getContext(), R.id.openExposureNotificationSettings, null); - return true; - }); - } else { - findPreference(PREF_EXPOSURE).setVisible(false); - } - - boolean checkinEnabled = CheckinPrefs.get(getContext()).isEnabled(); - findPreference(PREF_CHECKIN).setSummary(checkinEnabled ? R.string.service_status_enabled_short : R.string.service_status_disabled_short); - findPreference(PREF_CHECKIN).setOnPreferenceClickListener(preference -> { - UtilsKt.navigate(NavHostFragment.findNavController(SettingsFragment.this), getContext(), R.id.openCheckinSettings, null); - return true; - }); - } -} 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 new file mode 100644 index 00000000..d8902b8f --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/checkin/ServiceInfo.kt @@ -0,0 +1,93 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +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 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) + } + + 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) + } + } +} + + + +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 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/gcm/ServiceInfo.kt b/play-services-core/src/main/kotlin/org/microg/gms/gcm/ServiceInfo.kt new file mode 100644 index 00000000..ade5652d --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/gcm/ServiceInfo.kt @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.gcm + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.util.Log +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) : Serializable + +// TODO: Intervals +data class ServiceConfiguration(val enabled: Boolean, val confirmNewApps: Boolean) : Serializable { + fun saveToPrefs(context: Context) { + GcmPrefs.setEnabled(context, enabled) + // TODO: confirm new apps + } +} + +private fun GcmPrefs.toConfiguration(): ServiceConfiguration = ServiceConfiguration(isEnabled, isConfirmNewApps) + +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(), McsService.getStartTimestamp())) + }, 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) + } + } +} + +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 getGcmServiceInfo(context: Context): ServiceInfo = sendToServiceInfoReceiver( + 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) diff --git a/play-services-core/src/main/kotlin/org/microg/gms/gcm/StatusInfo.kt b/play-services-core/src/main/kotlin/org/microg/gms/gcm/StatusInfo.kt deleted file mode 100644 index 1797ca6c..00000000 --- a/play-services-core/src/main/kotlin/org/microg/gms/gcm/StatusInfo.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020, microG Project Team - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.microg.gms.gcm - -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import android.util.Log -import java.io.Serializable -import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine - -private const val ACTION_STATUS_INFO_REQUEST = "org.microg.gms.STATUS_INFO_REQUEST" -private const val ACTION_STATUS_INFO_RESPONSE = "org.microg.gms.STATUS_INFO_RESPONSE" -private const val EXTRA_STATUS_INFO = "org.microg.gms.STATUS_INFO" -private const val TAG = "GmsGcmStatusInfo" - -data class StatusInfo(val connected: Boolean, val startTimestamp: Long) : Serializable - -class StatusInfoProvider : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - try { - context.sendOrderedBroadcast(Intent(ACTION_STATUS_INFO_RESPONSE).apply { - setPackage(context.packageName) - putExtra(EXTRA_STATUS_INFO, StatusInfo(McsService.isConnected(), McsService.getStartTimestamp())) - }, null) - } catch (e: Exception) { - Log.w(TAG, e) - } - } -} - -suspend fun getStatusInfo(context: Context): StatusInfo? = suspendCoroutine { - context.registerReceiver(object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent?) { - try { - it.resume(intent?.getSerializableExtra(EXTRA_STATUS_INFO) as? StatusInfo) - } catch (e: Exception) { - Log.w(TAG, e) - } - context.unregisterReceiver(this) - } - }, IntentFilter(ACTION_STATUS_INFO_RESPONSE)) - try { - context.sendOrderedBroadcast(Intent(context, StatusInfoProvider::class.java), null) - } catch (e: Exception) { - it.resume(null) - } -} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/snet/ServiceInfo.kt b/play-services-core/src/main/kotlin/org/microg/gms/snet/ServiceInfo.kt new file mode 100644 index 00000000..2c045316 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/snet/ServiceInfo.kt @@ -0,0 +1,90 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.snet + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.util.Log +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.snet.SERVICE_INFO_REQUEST" +private const val ACTION_UPDATE_CONFIGURATION = "org.microg.gms.snet.UPDATE_CONFIGURATION" +private const val ACTION_SERVICE_INFO_RESPONSE = "org.microg.gms.snet.SERVICE_INFO_RESPONSE" +private const val EXTRA_SERVICE_INFO = "org.microg.gms.snet.SERVICE_INFO" +private const val EXTRA_CONFIGURATION = "org.microg.gms.snet.CONFIGURATION" +private const val TAG = "GmsSafetyNetStatusInfo" + +data class ServiceInfo(val configuration: ServiceConfiguration) : Serializable + +data class ServiceConfiguration(val enabled: Boolean) : Serializable { + fun saveToPrefs(context: Context) { + SafetyNetPrefs.get(context).isEnabled = enabled + } +} + +private fun SafetyNetPrefs.toConfiguration(): ServiceConfiguration = ServiceConfiguration(isEnabled) + +class ServiceInfoReceiver : BroadcastReceiver() { + private fun sendInfoResponse(context: Context) { + context.sendOrderedBroadcast(Intent(ACTION_SERVICE_INFO_RESPONSE).apply { + setPackage(context.packageName) + putExtra(EXTRA_SERVICE_INFO, ServiceInfo(SafetyNetPrefs.get(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) + } + } +} + +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 getSafetyNetServiceInfo(context: Context): ServiceInfo = sendToServiceInfoReceiver( + Intent(context, ServiceInfoReceiver::class.java).apply { + action = ACTION_SERVICE_INFO_REQUEST + }, context) + +suspend fun setSafetyNetServiceConfiguration(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/ui/DeviceRegistrationFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationFragment.kt index 5cece629..b56ec0dc 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 @@ -13,7 +13,9 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import com.google.android.gms.R import com.google.android.gms.databinding.DeviceRegistrationFragmentBinding -import org.microg.gms.checkin.CheckinPrefs +import org.microg.gms.checkin.ServiceInfo +import org.microg.gms.checkin.getCheckinServiceInfo +import org.microg.gms.checkin.setCheckinServiceConfiguration class DeviceRegistrationFragment : Fragment(R.layout.device_registration_fragment) { private lateinit var binding: DeviceRegistrationFragmentBinding @@ -22,17 +24,28 @@ class DeviceRegistrationFragment : Fragment(R.layout.device_registration_fragmen binding = DeviceRegistrationFragmentBinding.inflate(inflater, container, false) binding.switchBarCallback = object : PreferenceSwitchBarCallback { override fun onChecked(newStatus: Boolean) { - CheckinPrefs.setEnabled(context, newStatus) - binding.checkinEnabled = newStatus + setEnabled(newStatus) } } return binding.root } + fun setEnabled(newStatus: Boolean) { + lifecycleScope.launchWhenResumed { + val info = getCheckinServiceInfo(requireContext()) + val newConfiguration = info.configuration.copy(enabled = newStatus) + displayServiceInfo(setCheckinServiceConfiguration(requireContext(), newConfiguration)) + } + } + + fun displayServiceInfo(serviceInfo: ServiceInfo) { + binding.checkinEnabled = serviceInfo.configuration.enabled + } + override fun onResume() { super.onResume() lifecycleScope.launchWhenResumed { - binding.checkinEnabled = CheckinPrefs.get(context).isEnabled + displayServiceInfo(getCheckinServiceInfo(requireContext())) } } } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt index b1f53234..a9aa42ed 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/DeviceRegistrationPreferencesFragment.kt @@ -8,16 +8,17 @@ package org.microg.gms.ui import android.os.Bundle import android.os.Handler import android.text.format.DateUtils +import androidx.lifecycle.lifecycleScope import androidx.preference.Preference import androidx.preference.PreferenceCategory import androidx.preference.PreferenceFragmentCompat import com.google.android.gms.R -import org.microg.gms.checkin.CheckinPrefs -import org.microg.gms.checkin.LastCheckinInfo +import org.microg.gms.checkin.getCheckinServiceInfo class DeviceRegistrationPreferencesFragment : PreferenceFragmentCompat() { private lateinit var statusCategory: PreferenceCategory private lateinit var status: Preference + private lateinit var androidId: Preference private val handler = Handler() private val updateRunnable = Runnable { updateStatus() } @@ -28,6 +29,7 @@ class DeviceRegistrationPreferencesFragment : PreferenceFragmentCompat() { override fun onBindPreferences() { statusCategory = preferenceScreen.findPreference("prefcat_device_registration_status") ?: statusCategory status = preferenceScreen.findPreference("pref_device_registration_status") ?: status + androidId = preferenceScreen.findPreference("pref_device_registration_android_id") ?: androidId } override fun onResume() { @@ -42,12 +44,17 @@ class DeviceRegistrationPreferencesFragment : PreferenceFragmentCompat() { private fun updateStatus() { handler.postDelayed(updateRunnable, UPDATE_INTERVAL) - statusCategory.isVisible = CheckinPrefs.get(context).isEnabled - val checkinInfo = LastCheckinInfo.read(requireContext()) - status.summary = if (checkinInfo.lastCheckin > 0) { - getString(R.string.checkin_last_registration, DateUtils.getRelativeTimeSpanString(checkinInfo.lastCheckin, System.currentTimeMillis(), 0)) - } else { - getString(R.string.checkin_not_registered) + lifecycleScope.launchWhenResumed { + val serviceInfo = getCheckinServiceInfo(requireContext()) + statusCategory.isVisible = serviceInfo.configuration.enabled + if (serviceInfo.lastCheckin > 0) { + status.summary = getString(R.string.checkin_last_registration, DateUtils.getRelativeTimeSpanString(serviceInfo.lastCheckin, System.currentTimeMillis(), 0)) + androidId.isVisible = true + androidId.summary = serviceInfo.androidId.toString(16) + } else { + status.summary = getString(R.string.checkin_not_registered) + androidId.isVisible = false + } } } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsFragment.kt index 127c0db9..99051bcf 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsFragment.kt @@ -13,7 +13,9 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import com.google.android.gms.R import com.google.android.gms.databinding.ExposureNotificationsFragmentBinding -import org.microg.gms.nearby.exposurenotification.ExposurePreferences +import org.microg.gms.nearby.exposurenotification.ServiceInfo +import org.microg.gms.nearby.exposurenotification.getExposureNotificationsServiceInfo +import org.microg.gms.nearby.exposurenotification.setExposureNotificationsServiceConfiguration class ExposureNotificationsFragment : Fragment(R.layout.exposure_notifications_fragment) { private lateinit var binding: ExposureNotificationsFragmentBinding @@ -22,17 +24,28 @@ class ExposureNotificationsFragment : Fragment(R.layout.exposure_notifications_f binding = ExposureNotificationsFragmentBinding.inflate(inflater, container, false) binding.switchBarCallback = object : PreferenceSwitchBarCallback { override fun onChecked(newStatus: Boolean) { - ExposurePreferences(requireContext()).scannerEnabled = newStatus - binding.scannerEnabled = newStatus + setEnabled(newStatus) } } return binding.root } + fun setEnabled(newStatus: Boolean) { + lifecycleScope.launchWhenResumed { + val info = getExposureNotificationsServiceInfo(requireContext()) + val newConfiguration = info.configuration.copy(enabled = newStatus) + displayServiceInfo(setExposureNotificationsServiceConfiguration(requireContext(), newConfiguration)) + } + } + + fun displayServiceInfo(serviceInfo: ServiceInfo) { + binding.scannerEnabled = serviceInfo.configuration.enabled + } + override fun onResume() { super.onResume() lifecycleScope.launchWhenResumed { - binding.scannerEnabled = ExposurePreferences(requireContext()).scannerEnabled + displayServiceInfo(getExposureNotificationsServiceInfo(requireContext())) } } } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsPreferencesFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsPreferencesFragment.kt index 69bf37c5..e8666daf 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsPreferencesFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsPreferencesFragment.kt @@ -17,7 +17,7 @@ import com.google.android.gms.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.microg.gms.nearby.exposurenotification.ExposureDatabase -import org.microg.gms.nearby.exposurenotification.ExposurePreferences +import org.microg.gms.nearby.exposurenotification.getExposureNotificationsServiceInfo class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() { private lateinit var exposureEnableInfo: Preference @@ -62,9 +62,9 @@ class ExposureNotificationsPreferencesFragment : PreferenceFragmentCompat() { private fun updateStatus() { lifecycleScope.launchWhenResumed { handler.postDelayed(updateStatusRunnable, UPDATE_STATUS_INTERVAL) - val preferences = ExposurePreferences(requireContext()) - exposureEnableInfo.isVisible = !preferences.scannerEnabled - advertisingId.isVisible = preferences.advertiserEnabled + val enabled = getExposureNotificationsServiceInfo(requireContext()).configuration.enabled + exposureEnableInfo.isVisible = !enabled + advertisingId.isVisible = 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 2af9e2cf..f0e78ec2 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 @@ -11,8 +11,10 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import com.google.android.gms.R import com.google.android.gms.databinding.PushNotificationFragmentBinding -import org.microg.gms.checkin.CheckinPrefs -import org.microg.gms.gcm.GcmPrefs +import org.microg.gms.checkin.getCheckinServiceInfo +import org.microg.gms.gcm.ServiceInfo +import org.microg.gms.gcm.getGcmServiceInfo +import org.microg.gms.gcm.setGcmServiceConfiguration class PushNotificationFragment : Fragment(R.layout.push_notification_fragment) { lateinit var binding: PushNotificationFragmentBinding @@ -21,18 +23,29 @@ class PushNotificationFragment : Fragment(R.layout.push_notification_fragment) { binding = PushNotificationFragmentBinding.inflate(inflater, container, false) binding.switchBarCallback = object : PreferenceSwitchBarCallback { override fun onChecked(newStatus: Boolean) { - GcmPrefs.setEnabled(context, newStatus) - binding.gcmEnabled = newStatus + setEnabled(newStatus) } } return binding.root } + fun setEnabled(newStatus: Boolean) { + lifecycleScope.launchWhenResumed { + val info = getGcmServiceInfo(requireContext()) + val newConfiguration = info.configuration.copy(enabled = newStatus) + displayServiceInfo(setGcmServiceConfiguration(requireContext(), newConfiguration)) + } + } + + fun displayServiceInfo(serviceInfo: ServiceInfo) { + binding.gcmEnabled = serviceInfo.configuration.enabled + } + override fun onResume() { super.onResume() lifecycleScope.launchWhenResumed { - binding.gcmEnabled = GcmPrefs.get(context).isEnabled - binding.checkinEnabled = CheckinPrefs.get(context).isEnabled + displayServiceInfo(getGcmServiceInfo(requireContext())) + binding.checkinEnabled = getCheckinServiceInfo(requireContext()).configuration.enabled } } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationPreferencesFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationPreferencesFragment.kt index 9b5f8281..a0283ab9 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationPreferencesFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/PushNotificationPreferencesFragment.kt @@ -18,9 +18,7 @@ import com.google.android.gms.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.microg.gms.gcm.GcmDatabase -import org.microg.gms.gcm.GcmPrefs -import org.microg.gms.gcm.McsService -import org.microg.gms.gcm.getStatusInfo +import org.microg.gms.gcm.getGcmServiceInfo class PushNotificationPreferencesFragment : PreferenceFragmentCompat() { private lateinit var pushStatusCategory: PreferenceCategory @@ -67,9 +65,9 @@ class PushNotificationPreferencesFragment : PreferenceFragmentCompat() { private fun updateStatus() { handler.postDelayed(updateRunnable, UPDATE_INTERVAL) - pushStatusCategory.isVisible = GcmPrefs.get(context).isEnabled lifecycleScope.launchWhenStarted { - val statusInfo = getStatusInfo(requireContext()) + val statusInfo = getGcmServiceInfo(requireContext()) + pushStatusCategory.isVisible = statusInfo.configuration.enabled pushStatus.summary = if (statusInfo != null && statusInfo.connected) { getString(R.string.gcm_network_state_connected, DateUtils.getRelativeTimeSpanString(statusInfo.startTimestamp, System.currentTimeMillis(), 0)) } else { diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetFragment.kt index 7daf880d..030af985 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetFragment.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/SafetyNetFragment.kt @@ -8,11 +8,14 @@ package org.microg.gms.ui import android.os.Bundle import android.view.* import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import com.google.android.gms.R import com.google.android.gms.databinding.SafetyNetFragmentBinding -import org.microg.gms.checkin.CheckinPrefs -import org.microg.gms.snet.SafetyNetPrefs +import org.microg.gms.checkin.getCheckinServiceInfo +import org.microg.gms.snet.ServiceInfo +import org.microg.gms.snet.getSafetyNetServiceInfo +import org.microg.gms.snet.setSafetyNetServiceConfiguration class SafetyNetFragment : Fragment(R.layout.safety_net_fragment) { @@ -22,17 +25,30 @@ class SafetyNetFragment : Fragment(R.layout.safety_net_fragment) { binding = SafetyNetFragmentBinding.inflate(inflater, container, false) binding.switchBarCallback = object : PreferenceSwitchBarCallback { override fun onChecked(newStatus: Boolean) { - SafetyNetPrefs.get(requireContext()).isEnabled = newStatus - binding.safetynetEnabled = newStatus + setEnabled(newStatus) } } return binding.root } + fun setEnabled(newStatus: Boolean) { + lifecycleScope.launchWhenResumed { + val info = getSafetyNetServiceInfo(requireContext()) + val newConfiguration = info.configuration.copy(enabled = newStatus) + displayServiceInfo(setSafetyNetServiceConfiguration(requireContext(), newConfiguration)) + } + } + + fun displayServiceInfo(serviceInfo: ServiceInfo) { + binding.safetynetEnabled = serviceInfo.configuration.enabled + } + override fun onResume() { super.onResume() - binding.checkinEnabled = CheckinPrefs.get(requireContext()).isEnabled - binding.safetynetEnabled = SafetyNetPrefs.get(requireContext()).isEnabled + lifecycleScope.launchWhenResumed { + binding.checkinEnabled = getCheckinServiceInfo(requireContext()).configuration.enabled + displayServiceInfo(getSafetyNetServiceInfo(requireContext())) + } } override fun onActivityCreated(savedInstanceState: Bundle?) { diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt new file mode 100644 index 00000000..8f296434 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/SettingsFragment.kt @@ -0,0 +1,100 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.ui + +import android.os.Build +import android.os.Bundle +import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.findNavController +import androidx.preference.Preference +import com.google.android.gms.R +import org.microg.gms.checkin.getCheckinServiceInfo +import org.microg.gms.gcm.GcmDatabase +import org.microg.gms.gcm.getGcmServiceInfo +import org.microg.gms.nearby.exposurenotification.getExposureNotificationsServiceInfo +import org.microg.gms.snet.getSafetyNetServiceInfo +import org.microg.nlp.client.UnifiedLocationClient +import org.microg.tools.ui.ResourceSettingsFragment + +class SettingsFragment : ResourceSettingsFragment() { + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + super.onCreatePreferences(savedInstanceState, rootKey) + + findPreference(PREF_CHECKIN)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + findNavController().navigate(requireContext(), R.id.openCheckinSettings) + true + } + findPreference(PREF_GCM)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + findNavController().navigate(requireContext(), R.id.openGcmSettings) + true + } + findPreference(PREF_SNET)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + findNavController().navigate(requireContext(), R.id.openSafetyNetSettings) + true + } + findPreference(PREF_UNIFIEDNLP)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + findNavController().navigate(requireContext(), R.id.openUnifiedNlpSettings) + true + } + findPreference(PREF_EXPOSURE)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + findNavController().navigate(requireContext(), R.id.openExposureNotificationSettings) + true + } + findPreference(PREF_ABOUT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + findNavController().navigate(requireContext(), R.id.openAbout) + true + } + findPreference(PREF_ABOUT)!!.summary = getString(R.string.about_version_str, AboutFragment.getSelfVersion(context)) + } + + override fun onResume() { + super.onResume() + lifecycleScope.launchWhenResumed { + updateDetails() + } + } + + private suspend fun updateDetails() { + if (getGcmServiceInfo(requireContext()).configuration.enabled) { + val database = GcmDatabase(context) + val regCount = database.registrationList.size + database.close() + findPreference(PREF_GCM)!!.summary = getString(R.string.service_status_enabled_short) + " - " + resources.getQuantityString(R.plurals.gcm_registered_apps_counter, regCount, regCount) + } else { + findPreference(PREF_GCM)!!.setSummary(R.string.service_status_disabled_short) + } + + findPreference(PREF_CHECKIN)!!.setSummary(if (getCheckinServiceInfo(requireContext()).configuration.enabled) R.string.service_status_enabled_short else R.string.service_status_disabled_short) + findPreference(PREF_SNET)!!.setSummary(if (getSafetyNetServiceInfo(requireContext()).configuration.enabled) R.string.service_status_enabled_short else R.string.service_status_disabled_short) + + val backendCount = UnifiedLocationClient[requireContext()].getLocationBackends().size + UnifiedLocationClient[requireContext()].getGeocoderBackends().size + findPreference(PREF_UNIFIEDNLP)!!.summary = resources.getQuantityString(R.plurals.pref_unifiednlp_summary, backendCount, backendCount); + + if (Build.VERSION.SDK_INT >= 21) { + findPreference(PREF_EXPOSURE)!!.isVisible = true + if (getExposureNotificationsServiceInfo(requireContext()).configuration.enabled) { + findPreference(PREF_EXPOSURE)!!.summary = getString(R.string.service_status_enabled_short) + } else { + findPreference(PREF_EXPOSURE)!!.setSummary(R.string.service_status_disabled_short) + } + } else { + findPreference(PREF_EXPOSURE)!!.isVisible = false + } + } + + companion object { + const val PREF_ABOUT = "pref_about" + const val PREF_GCM = "pref_gcm" + const val PREF_SNET = "pref_snet" + const val PREF_UNIFIEDNLP = "pref_unifiednlp" + const val PREF_CHECKIN = "pref_checkin" + const val PREF_EXPOSURE = "pref_exposure" + } + + init { + preferencesResource = R.xml.preferences_start + } +} diff --git a/play-services-core/src/main/res/values/strings.xml b/play-services-core/src/main/res/values/strings.xml index 6fcc35a8..70e991a2 100644 --- a/play-services-core/src/main/res/values/strings.xml +++ b/play-services-core/src/main/res/values/strings.xml @@ -140,6 +140,7 @@ This can take a couple of minutes." When enabled, all applications on this device will be able to see email address of your Google Accounts without prior authorization. Registers your device to Google services and creates a unique device identifier. microG strips identifying bits other than your Google account name from registration data. + Android ID Not registered Last registration: %1$s diff --git a/play-services-core/src/main/res/xml/preferences_device_registration.xml b/play-services-core/src/main/res/xml/preferences_device_registration.xml index 7773de62..1f73af33 100644 --- a/play-services-core/src/main/res/xml/preferences_device_registration.xml +++ b/play-services-core/src/main/res/xml/preferences_device_registration.xml @@ -14,6 +14,11 @@ android:selectable="false" android:title="@string/pref_info_status" tools:summary="Last registration: 13 hours ago" /> +