mirror of
https://github.com/TeamVanced/VancedMicroG
synced 2024-12-24 03:35:50 +01:00
Fix UI mismatching actual configuration due to multiprocess
This commit is contained in:
parent
3ef330ad7b
commit
d641ca7e7e
@ -193,6 +193,8 @@
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<receiver android:name="org.microg.gms.checkin.ServiceInfoReceiver" />
|
||||
|
||||
<receiver android:name="org.microg.gms.checkin.TriggerReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.server.checkin.CHECKIN" />
|
||||
@ -238,7 +240,7 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="org.microg.gms.gcm.StatusInfoProvider" />
|
||||
<receiver android:name="org.microg.gms.gcm.ServiceInfoReceiver" />
|
||||
|
||||
<receiver android:name="org.microg.gms.gcm.TriggerReceiver">
|
||||
<intent-filter>
|
||||
@ -627,6 +629,8 @@
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<receiver android:name="org.microg.gms.snet.ServiceInfoReceiver" />
|
||||
|
||||
<service android:name="org.microg.gms.snet.SafetyNetClientService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.safetynet.service.START" />
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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<ResolveInfo> 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:
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
@ -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)
|
@ -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)
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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?) {
|
||||
|
@ -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<Preference>(PREF_CHECKIN)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
findNavController().navigate(requireContext(), R.id.openCheckinSettings)
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(PREF_GCM)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
findNavController().navigate(requireContext(), R.id.openGcmSettings)
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(PREF_SNET)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
findNavController().navigate(requireContext(), R.id.openSafetyNetSettings)
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(PREF_UNIFIEDNLP)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
findNavController().navigate(requireContext(), R.id.openUnifiedNlpSettings)
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(PREF_EXPOSURE)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
findNavController().navigate(requireContext(), R.id.openExposureNotificationSettings)
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(PREF_ABOUT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
findNavController().navigate(requireContext(), R.id.openAbout)
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(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<Preference>(PREF_GCM)!!.summary = getString(R.string.service_status_enabled_short) + " - " + resources.getQuantityString(R.plurals.gcm_registered_apps_counter, regCount, regCount)
|
||||
} else {
|
||||
findPreference<Preference>(PREF_GCM)!!.setSummary(R.string.service_status_disabled_short)
|
||||
}
|
||||
|
||||
findPreference<Preference>(PREF_CHECKIN)!!.setSummary(if (getCheckinServiceInfo(requireContext()).configuration.enabled) R.string.service_status_enabled_short else R.string.service_status_disabled_short)
|
||||
findPreference<Preference>(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<Preference>(PREF_UNIFIEDNLP)!!.summary = resources.getQuantityString(R.plurals.pref_unifiednlp_summary, backendCount, backendCount);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
findPreference<Preference>(PREF_EXPOSURE)!!.isVisible = true
|
||||
if (getExposureNotificationsServiceInfo(requireContext()).configuration.enabled) {
|
||||
findPreference<Preference>(PREF_EXPOSURE)!!.summary = getString(R.string.service_status_enabled_short)
|
||||
} else {
|
||||
findPreference<Preference>(PREF_EXPOSURE)!!.setSummary(R.string.service_status_disabled_short)
|
||||
}
|
||||
} else {
|
||||
findPreference<Preference>(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
|
||||
}
|
||||
}
|
@ -140,6 +140,7 @@ This can take a couple of minutes."</string>
|
||||
<string name="pref_auth_visible_summary">When enabled, all applications on this device will be able to see email address of your Google Accounts without prior authorization.</string>
|
||||
|
||||
<string name="pref_checkin_enable_summary">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.</string>
|
||||
<string name="pref_device_registration_android_id">Android ID</string>
|
||||
|
||||
<string name="checkin_not_registered">Not registered</string>
|
||||
<string name="checkin_last_registration">Last registration: <xliff:g example="Yesterday, 02:20 PM">%1$s</xliff:g></string>
|
||||
|
@ -14,6 +14,11 @@
|
||||
android:selectable="false"
|
||||
android:title="@string/pref_info_status"
|
||||
tools:summary="Last registration: 13 hours ago" />
|
||||
<Preference
|
||||
android:key="pref_device_registration_android_id"
|
||||
android:selectable="false"
|
||||
android:title="@string/pref_device_registration_android_id"
|
||||
tools:summary="1953a59d1c1b7e4b" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:layout="@layout/preference_category_no_label">
|
||||
<org.microg.gms.ui.TextPreference
|
||||
|
Loading…
Reference in New Issue
Block a user