mirror of
https://github.com/TeamVanced/VancedMicroG
synced 2024-12-29 06:05:47 +01:00
Update to latest upstream
This commit is contained in:
parent
ba1ee758be
commit
79f78b8d86
@ -39,6 +39,6 @@ dependencies {
|
||||
api project(':play-services-tasks')
|
||||
api project(':play-services-base-api')
|
||||
|
||||
implementation 'androidx.fragment:fragment:1.3.3'
|
||||
implementation 'androidx.fragment:fragment:1.3.5'
|
||||
implementation 'com.google.android.gms:play-services-base:17.6.0'
|
||||
}
|
@ -7,7 +7,7 @@ apply plugin: 'com.squareup.wire'
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
dependencies {
|
||||
implementation "com.squareup.wire:wire-runtime:$wireVersion"
|
||||
implementation "com.squareup.wire:wire-runtime:3.6.1"
|
||||
}
|
||||
|
||||
wire {
|
||||
|
@ -32,8 +32,8 @@ dependencies {
|
||||
implementation project(':play-services-cast-api')
|
||||
|
||||
// AndroidX UI
|
||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||
implementation 'androidx.mediarouter:mediarouter:1.2.3'
|
||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
||||
implementation 'androidx.mediarouter:mediarouter:1.2.4'
|
||||
implementation "androidx.preference:preference-ktx:$preferenceVersion"
|
||||
|
||||
implementation "org.microg.gms:conscrypt-gmscore:2.5.1"
|
||||
@ -45,7 +45,7 @@ dependencies {
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-service:2.3.1"
|
||||
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.31'
|
||||
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32'
|
||||
|
||||
api project(':play-services-basement')
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
||||
implementation "androidx.preference:preference:$preferenceVersion"
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,13 @@
|
||||
android:name="fake-signature"
|
||||
android:value="@string/fake_signature" />
|
||||
|
||||
<!-- Internal Settings -->
|
||||
|
||||
<provider
|
||||
android:name="org.microg.gms.settings.SettingsProvider"
|
||||
android:authorities="org.microg.gms.settings"
|
||||
android:exported="true" />
|
||||
|
||||
<!-- Services Framework -->
|
||||
|
||||
<provider
|
||||
@ -117,8 +124,6 @@
|
||||
</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.intent.action.BOOT_COMPLETED" />
|
||||
@ -303,6 +308,12 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Fonts -->
|
||||
<provider
|
||||
android:name="org.microg.gms.fonts.FontsProvider"
|
||||
android:authorities="com.mgoogle.android.gms.fonts"
|
||||
android:exported="true"/>
|
||||
|
||||
<!-- microG Settings shown in Launcher -->
|
||||
<activity-alias
|
||||
android:name="org.microg.gms.ui.SettingsActivityLauncher"
|
||||
|
@ -23,21 +23,20 @@ import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.microg.gms.common.PackageUtils;
|
||||
import org.microg.gms.settings.SettingsContract;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
|
||||
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
||||
import static org.microg.gms.auth.AuthPrefs.isTrustGooglePermitted;
|
||||
|
||||
public class AuthManager {
|
||||
|
||||
private static final String TAG = "GmsAuthManager";
|
||||
public static final String PERMISSION_TREE_BASE = "com.mgoogle.android.googleapps.permission.GOOGLE_AUTH.";
|
||||
private static final String PREF_AUTH_TRUST_GOOGLE = "auth_manager_trust_google";
|
||||
public static final String PREF_AUTH_VISIBLE = "auth_manager_visible";
|
||||
public static final String PREF_AUTH_VISIBLE = SettingsContract.Auth.VISIBLE;
|
||||
public static final int ONE_HOUR_IN_SECONDS = 60 * 60;
|
||||
|
||||
private final Context context;
|
||||
@ -194,14 +193,6 @@ public class AuthManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isTrustGooglePermitted(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_AUTH_TRUST_GOOGLE, true);
|
||||
}
|
||||
|
||||
public static boolean isAuthVisible(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_AUTH_VISIBLE, false);
|
||||
}
|
||||
|
||||
private boolean isSystemApp() {
|
||||
try {
|
||||
int flags = context.getPackageManager().getApplicationInfo(packageName, 0).flags;
|
||||
|
@ -113,7 +113,7 @@ public class AuthRequest extends HttpFormClient.Request {
|
||||
public AuthRequest fromContext(Context context) {
|
||||
build(Utils.getBuild(context));
|
||||
locale(Utils.getLocale(context));
|
||||
androidIdHex = Long.toHexString(LastCheckinInfo.read(context).androidId);
|
||||
androidIdHex = Long.toHexString(LastCheckinInfo.read(context).getAndroidId());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,7 @@ import static android.view.KeyEvent.KEYCODE_BACK;
|
||||
import static android.view.View.INVISIBLE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
|
||||
import static org.microg.gms.auth.AuthPrefs.isAuthVisible;
|
||||
import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
|
||||
import static org.microg.gms.common.Constants.GMS_VERSION_CODE;
|
||||
|
||||
@ -141,7 +142,7 @@ public class LoginActivity extends AssistantActivity {
|
||||
AccountManager accountManager = AccountManager.get(this);
|
||||
Account account = new Account(getIntent().getStringExtra(EXTRA_EMAIL), accountType);
|
||||
accountManager.addAccountExplicitly(account, getIntent().getStringExtra(EXTRA_TOKEN), null);
|
||||
if (AuthManager.isAuthVisible(this) && SDK_INT >= Build.VERSION_CODES.O) {
|
||||
if (isAuthVisible(this) && SDK_INT >= Build.VERSION_CODES.O) {
|
||||
accountManager.setAccountVisibility(account, PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, VISIBILITY_USER_MANAGED_VISIBLE);
|
||||
}
|
||||
retrieveGmsToken(account);
|
||||
@ -167,7 +168,7 @@ public class LoginActivity extends AssistantActivity {
|
||||
}
|
||||
PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean(HuaweiButtonPreference, true).apply();
|
||||
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(LoginButtonPreference, true)) {
|
||||
LastCheckinInfo.ClearCheckinInfo(this);
|
||||
LastCheckinInfo.clear(this);
|
||||
CheckinClient.brandSpoof = true;
|
||||
PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean(LoginButtonPreference, true).apply();
|
||||
}
|
||||
@ -182,7 +183,7 @@ public class LoginActivity extends AssistantActivity {
|
||||
if (state == 1) {
|
||||
PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean(LoginButtonPreference, true).apply();
|
||||
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(HuaweiButtonPreference, true)) {
|
||||
LastCheckinInfo.ClearCheckinInfo(this);
|
||||
LastCheckinInfo.clear(this);
|
||||
CheckinClient.brandSpoof = false;
|
||||
PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean(HuaweiButtonPreference, true).apply();
|
||||
}
|
||||
@ -253,7 +254,7 @@ public class LoginActivity extends AssistantActivity {
|
||||
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
|
||||
if (networkInfo != null && networkInfo.isConnected()) {
|
||||
if (LastCheckinInfo.read(this).androidId == 0) {
|
||||
if (LastCheckinInfo.read(this).getAndroidId() == 0) {
|
||||
new Thread(() -> {
|
||||
Runnable next;
|
||||
next = checkin(false) ? this::loadLoginPage : () -> showError(R.string.auth_general_error_desc);
|
||||
@ -454,7 +455,7 @@ public class LoginActivity extends AssistantActivity {
|
||||
|
||||
@JavascriptInterface
|
||||
public final String getAndroidId() {
|
||||
long androidId = LastCheckinInfo.read(LoginActivity.this).androidId;
|
||||
long androidId = LastCheckinInfo.read(LoginActivity.this).getAndroidId();
|
||||
Log.d(TAG, "JSBridge: getAndroidId " + androidId);
|
||||
if (androidId == 0 || androidId == -1) return null;
|
||||
return Long.toHexString(androidId);
|
||||
|
@ -81,8 +81,8 @@ public class CheckinClient {
|
||||
LastCheckinInfo checkinInfo, Locale locale,
|
||||
List<Account> accounts) {
|
||||
CheckinRequest.Builder builder = new CheckinRequest.Builder()
|
||||
.accountCookie(new ArrayList<String>())
|
||||
.androidId(checkinInfo.androidId)
|
||||
.accountCookie(new ArrayList<>())
|
||||
.androidId(checkinInfo.getAndroidId())
|
||||
.checkin(new CheckinRequest.Checkin.Builder()
|
||||
.build(new CheckinRequest.Checkin.Build.Builder()
|
||||
.bootloader(brandSpoof ? "c2f2-0.2-5799621" : build.bootloader)
|
||||
@ -101,11 +101,11 @@ public class CheckinClient {
|
||||
.build())
|
||||
.cellOperator(phoneInfo.cellOperator)
|
||||
.event(Collections.singletonList(new CheckinRequest.Checkin.Event.Builder()
|
||||
.tag(checkinInfo.androidId == 0 ? "event_log_start" : "system_update")
|
||||
.value(checkinInfo.androidId == 0 ? null : "1536,0,-1,NULL")
|
||||
.tag(checkinInfo.getAndroidId() == 0 ? "event_log_start" : "system_update")
|
||||
.value(checkinInfo.getAndroidId() == 0 ? null : "1536,0,-1,NULL")
|
||||
.timeMs(new Date().getTime())
|
||||
.build()))
|
||||
.lastCheckinMs(checkinInfo.lastCheckin)
|
||||
.lastCheckinMs(checkinInfo.getLastCheckin())
|
||||
.requestedGroup(TODO_LIST_STRING)
|
||||
.roaming(phoneInfo.roaming)
|
||||
.simOperator(phoneInfo.simOperator)
|
||||
@ -129,7 +129,7 @@ public class CheckinClient {
|
||||
.touchScreen(deviceConfiguration.touchScreen)
|
||||
.widthPixels(deviceConfiguration.widthPixels)
|
||||
.build())
|
||||
.digest(checkinInfo.digest)
|
||||
.digest(checkinInfo.getDigest())
|
||||
.esn(deviceIdent.esn)
|
||||
.fragment(0)
|
||||
.locale(locale.toString())
|
||||
@ -150,8 +150,8 @@ public class CheckinClient {
|
||||
builder.macAddress(Collections.singletonList(deviceIdent.wifiMac))
|
||||
.macAddressType(Collections.singletonList("wifi"));
|
||||
}
|
||||
if (checkinInfo.securityToken != 0) {
|
||||
builder.securityToken(checkinInfo.securityToken)
|
||||
if (checkinInfo.getSecurityToken() != 0) {
|
||||
builder.securityToken(checkinInfo.getSecurityToken())
|
||||
.fragment(1);
|
||||
}
|
||||
return builder.build();
|
||||
|
@ -39,9 +39,9 @@ public class CheckinManager {
|
||||
@SuppressWarnings("MissingPermission")
|
||||
public static synchronized LastCheckinInfo checkin(Context context, boolean force) throws IOException {
|
||||
LastCheckinInfo info = LastCheckinInfo.read(context);
|
||||
if (!force && info.lastCheckin > System.currentTimeMillis() - MIN_CHECKIN_INTERVAL)
|
||||
if (!force && info.getLastCheckin() > System.currentTimeMillis() - MIN_CHECKIN_INTERVAL)
|
||||
return null;
|
||||
if (!CheckinPrefs.get(context).isEnabled())
|
||||
if (!CheckinPrefs.isEnabled(context))
|
||||
return null;
|
||||
List<CheckinClient.Account> accounts = new ArrayList<>();
|
||||
AccountManager accountManager = AccountManager.get(context);
|
||||
@ -63,13 +63,7 @@ public class CheckinManager {
|
||||
}
|
||||
|
||||
private static LastCheckinInfo handleResponse(Context context, CheckinResponse response) {
|
||||
LastCheckinInfo info = new LastCheckinInfo();
|
||||
info.androidId = response.androidId;
|
||||
info.lastCheckin = response.timeMs;
|
||||
info.securityToken = response.securityToken;
|
||||
info.digest = response.digest;
|
||||
info.versionInfo = response.versionInfo;
|
||||
info.deviceDataVersionInfo = response.deviceDataVersionInfo;
|
||||
LastCheckinInfo info = new LastCheckinInfo(response);
|
||||
info.write(context);
|
||||
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.checkin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import org.microg.gms.common.PackageUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class CheckinPrefs implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public static final String PREF_ENABLE_CHECKIN = "checkin_enable_service";
|
||||
private static CheckinPrefs INSTANCE;
|
||||
|
||||
public static CheckinPrefs get(Context context) {
|
||||
if (INSTANCE == null) {
|
||||
PackageUtils.warnIfNotMainProcess(context, CheckinPrefs.class);
|
||||
if (context == null) return new CheckinPrefs(null);
|
||||
INSTANCE = new CheckinPrefs(context.getApplicationContext());
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private SharedPreferences preferences;
|
||||
private SharedPreferences systemDefaultPreferences;
|
||||
private boolean checkinEnabled = false;
|
||||
|
||||
private CheckinPrefs(Context context) {
|
||||
if (context != null) {
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
try {
|
||||
systemDefaultPreferences = (SharedPreferences) Context.class.getDeclaredMethod("getSharedPreferences", File.class, int.class).invoke(context, new File("/system/etc/microg.xml"), Context.MODE_PRIVATE);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getSettingsBoolean(String key, boolean def) {
|
||||
if (systemDefaultPreferences != null) {
|
||||
def = systemDefaultPreferences.getBoolean(key, def);
|
||||
}
|
||||
return preferences.getBoolean(key, def);
|
||||
}
|
||||
|
||||
private void update() {
|
||||
checkinEnabled = getSettingsBoolean(PREF_ENABLE_CHECKIN, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
update();
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return checkinEnabled;
|
||||
}
|
||||
|
||||
public static void setEnabled(Context context, boolean newStatus) {
|
||||
boolean changed = CheckinPrefs.get(context).isEnabled() != newStatus;
|
||||
PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(PREF_ENABLE_CHECKIN, newStatus).apply();
|
||||
if (!changed) return;
|
||||
if (newStatus) {
|
||||
context.sendOrderedBroadcast(new Intent(context, TriggerReceiver.class), null);
|
||||
}
|
||||
}
|
||||
}
|
@ -57,7 +57,7 @@ public class CheckinService extends IntentService {
|
||||
private ICheckinService iface = new ICheckinService.Stub() {
|
||||
@Override
|
||||
public String getDeviceDataVersionInfo() throws RemoteException {
|
||||
return LastCheckinInfo.read(CheckinService.this).deviceDataVersionInfo;
|
||||
return LastCheckinInfo.read(CheckinService.this).getDeviceDataVersionInfo();
|
||||
}
|
||||
};
|
||||
|
||||
@ -70,10 +70,10 @@ public class CheckinService extends IntentService {
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
try {
|
||||
ForegroundServiceContext.completeForegroundService(this, intent, TAG);
|
||||
if (CheckinPrefs.get(this).isEnabled()) {
|
||||
if (CheckinPrefs.isEnabled(this)) {
|
||||
LastCheckinInfo info = CheckinManager.checkin(this, intent.getBooleanExtra(EXTRA_FORCE_CHECKIN, false));
|
||||
if (info != null) {
|
||||
Log.d(TAG, "Checked in as " + Long.toHexString(info.androidId));
|
||||
Log.d(TAG, "Checked in as " + Long.toHexString(info.getAndroidId()));
|
||||
String accountType = AuthConstants.DEFAULT_ACCOUNT_TYPE;
|
||||
for (Account account : AccountManager.get(this).getAccountsByType(accountType)) {
|
||||
PeopleManager.loadUserInfo(this, account);
|
||||
@ -86,7 +86,7 @@ public class CheckinService extends IntentService {
|
||||
ResultReceiver receiver = intent.getParcelableExtra(EXTRA_RESULT_RECEIVER);
|
||||
if (receiver != null) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putLong(EXTRA_NEW_CHECKIN_TIME, info.lastCheckin);
|
||||
bundle.putLong(EXTRA_NEW_CHECKIN_TIME, info.getLastCheckin());
|
||||
receiver.send(Activity.RESULT_OK, bundle);
|
||||
}
|
||||
}
|
||||
@ -115,6 +115,6 @@ public class CheckinService extends IntentService {
|
||||
static void schedule(Context context) {
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(context, TriggerReceiver.class.getName().hashCode(), new Intent(context, TriggerReceiver.class), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
alarmManager.set(AlarmManager.RTC, Math.max(LastCheckinInfo.read(context).lastCheckin + REGULAR_CHECKIN_INTERVAL, System.currentTimeMillis() + BACKUP_CHECKIN_DELAY), pendingIntent);
|
||||
alarmManager.set(AlarmManager.RTC, Math.max(LastCheckinInfo.read(context).getLastCheckin() + REGULAR_CHECKIN_INTERVAL, System.currentTimeMillis() + BACKUP_CHECKIN_DELAY), pendingIntent);
|
||||
}
|
||||
}
|
||||
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2017 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.checkin;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
public class LastCheckinInfo {
|
||||
public static final String PREFERENCES_NAME = "checkin";
|
||||
public static final String PREF_ANDROID_ID = "androidId";
|
||||
public static final String PREF_DIGEST = "digest";
|
||||
public static final String PREF_LAST_CHECKIN = "lastCheckin";
|
||||
public static final String PREF_SECURITY_TOKEN = "securityToken";
|
||||
public static final String PREF_VERSION_INFO = "versionInfo";
|
||||
public static final String PREF_DEVICE_DATA_VERSION_INFO = "deviceDataVersionInfo";
|
||||
public static final String INITIAL_DIGEST = "1-929a0dca0eee55513280171a8585da7dcd3700f8";
|
||||
public long lastCheckin;
|
||||
public long androidId;
|
||||
public long securityToken;
|
||||
public String digest;
|
||||
public String versionInfo;
|
||||
public String deviceDataVersionInfo;
|
||||
|
||||
public static LastCheckinInfo read(Context context) {
|
||||
LastCheckinInfo info = new LastCheckinInfo();
|
||||
SharedPreferences preferences = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
info.androidId = preferences.getLong(PREF_ANDROID_ID, 0);
|
||||
info.digest = preferences.getString(PREF_DIGEST, INITIAL_DIGEST);
|
||||
info.lastCheckin = preferences.getLong(PREF_LAST_CHECKIN, 0);
|
||||
info.securityToken = preferences.getLong(PREF_SECURITY_TOKEN, 0);
|
||||
info.versionInfo = preferences.getString(PREF_VERSION_INFO, "");
|
||||
info.deviceDataVersionInfo = preferences.getString(PREF_DEVICE_DATA_VERSION_INFO, "");
|
||||
return info;
|
||||
}
|
||||
|
||||
public void write(Context context) {
|
||||
context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE).edit()
|
||||
.putLong(PREF_ANDROID_ID, androidId)
|
||||
.putString(PREF_DIGEST, digest)
|
||||
.putLong(PREF_LAST_CHECKIN, lastCheckin)
|
||||
.putLong(PREF_SECURITY_TOKEN, securityToken)
|
||||
.putString(PREF_VERSION_INFO, versionInfo)
|
||||
.putString(PREF_DEVICE_DATA_VERSION_INFO, deviceDataVersionInfo)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static void ClearCheckinInfo(Context context) {
|
||||
context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE).edit()
|
||||
.putLong(PREF_ANDROID_ID, 0)
|
||||
.putString(PREF_DIGEST, INITIAL_DIGEST)
|
||||
.putLong(PREF_LAST_CHECKIN, 0)
|
||||
.putLong(PREF_SECURITY_TOKEN, 0)
|
||||
.putString(PREF_VERSION_INFO, "")
|
||||
.putString(PREF_DEVICE_DATA_VERSION_INFO, "")
|
||||
.commit();
|
||||
}
|
||||
}
|
@ -16,16 +16,21 @@
|
||||
|
||||
package org.microg.gms.checkin;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkRequest;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.legacy.content.WakefulBroadcastReceiver;
|
||||
|
||||
import org.microg.gms.common.ForegroundServiceContext;
|
||||
|
||||
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static org.microg.gms.checkin.CheckinService.EXTRA_FORCE_CHECKIN;
|
||||
import static org.microg.gms.checkin.CheckinService.REGULAR_CHECKIN_INTERVAL;
|
||||
|
||||
@ -37,8 +42,8 @@ public class TriggerReceiver extends WakefulBroadcastReceiver {
|
||||
try {
|
||||
boolean force = "android.provider.Telephony.SECRET_CODE".equals(intent.getAction());
|
||||
|
||||
if (CheckinPrefs.get(context).isEnabled() || force) {
|
||||
if (LastCheckinInfo.read(context).lastCheckin > System.currentTimeMillis() - REGULAR_CHECKIN_INTERVAL && !force) {
|
||||
if (CheckinPrefs.isEnabled(context) || force) {
|
||||
if (LastCheckinInfo.read(context).getLastCheckin() > System.currentTimeMillis() - REGULAR_CHECKIN_INTERVAL && !force) {
|
||||
CheckinService.schedule(context);
|
||||
return;
|
||||
}
|
||||
@ -49,7 +54,15 @@ public class TriggerReceiver extends WakefulBroadcastReceiver {
|
||||
Intent subIntent = new Intent(context, CheckinService.class);
|
||||
subIntent.putExtra(EXTRA_FORCE_CHECKIN, force);
|
||||
startWakefulService(new ForegroundServiceContext(context), subIntent);
|
||||
}
|
||||
} else if (SDK_INT >= 23) {
|
||||
// no network, register a network callback to retry when we have internet
|
||||
NetworkRequest networkRequest = new NetworkRequest.Builder()
|
||||
.addCapability(NET_CAPABILITY_INTERNET)
|
||||
.build();
|
||||
Intent i = new Intent(context, TriggerReceiver.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, i, FLAG_UPDATE_CURRENT);
|
||||
cm.registerNetworkCallback(networkRequest, pendingIntent);
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Ignoring " + intent + ": checkin is disabled");
|
||||
}
|
||||
|
@ -1,291 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2017 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.gcm;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.microg.gms.common.PackageUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class GcmPrefs implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public static final String PREF_FULL_LOG = "gcm_full_log";
|
||||
public static final String PREF_LAST_PERSISTENT_ID = "gcm_last_persistent_id";
|
||||
public static final String PREF_CONFIRM_NEW_APPS = "gcm_confirm_new_apps";
|
||||
public static final String PREF_ENABLE_GCM = "gcm_enable_mcs_service";
|
||||
|
||||
public static final String PREF_NETWORK_MOBILE = "gcm_network_mobile";
|
||||
public static final String PREF_NETWORK_WIFI = "gcm_network_wifi";
|
||||
public static final String PREF_NETWORK_ROAMING = "gcm_network_roaming";
|
||||
public static final String PREF_NETWORK_OTHER = "gcm_network_other";
|
||||
|
||||
public static final String PREF_LEARNT_MOBILE = "gcm_learnt_mobile";
|
||||
public static final String PREF_LEARNT_WIFI = "gcm_learnt_wifi";
|
||||
public static final String PREF_LEARNT_OTHER = "gcm_learnt_other";
|
||||
|
||||
private static final int INTERVAL = 1 * 60 * 1000; // 1 minute
|
||||
|
||||
private static GcmPrefs INSTANCE;
|
||||
|
||||
public static GcmPrefs get(Context context) {
|
||||
if (INSTANCE == null) {
|
||||
PackageUtils.warnIfNotPersistentProcess(GcmPrefs.class);
|
||||
INSTANCE = new GcmPrefs(context.getApplicationContext());
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private boolean gcmLogEnabled = true;
|
||||
private String lastPersistedId = "";
|
||||
private boolean gcmEnabled = false;
|
||||
|
||||
private int networkMobile = 0;
|
||||
private int networkWifi = 0;
|
||||
private int networkRoaming = 0;
|
||||
private int networkOther = 0;
|
||||
|
||||
private int learntWifi = 300000;
|
||||
private int learntMobile = 300000;
|
||||
private int learntOther = 300000;
|
||||
|
||||
private final Context context;
|
||||
private SharedPreferences preferences;
|
||||
private SharedPreferences systemDefaultPreferences;
|
||||
|
||||
private GcmPrefs(Context context) {
|
||||
this.context = context;
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
try {
|
||||
systemDefaultPreferences = (SharedPreferences) Context.class.getDeclaredMethod("getSharedPreferences", File.class, int.class).invoke(context, new File("/system/etc/microg.xml"), Context.MODE_PRIVATE);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
private boolean getSettingsBoolean(String key, boolean def) {
|
||||
if (systemDefaultPreferences != null) {
|
||||
def = systemDefaultPreferences.getBoolean(key, def);
|
||||
}
|
||||
return preferences.getBoolean(key, def);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
gcmEnabled = getSettingsBoolean(PREF_ENABLE_GCM, true);
|
||||
gcmLogEnabled = getSettingsBoolean(PREF_FULL_LOG, true);
|
||||
|
||||
lastPersistedId = preferences.getString(PREF_LAST_PERSISTENT_ID, "");
|
||||
|
||||
networkMobile = Integer.parseInt(preferences.getString(PREF_NETWORK_MOBILE, "0"));
|
||||
networkWifi = Integer.parseInt(preferences.getString(PREF_NETWORK_WIFI, "0"));
|
||||
networkRoaming = Integer.parseInt(preferences.getString(PREF_NETWORK_ROAMING, "0"));
|
||||
networkOther = Integer.parseInt(preferences.getString(PREF_NETWORK_OTHER, "0"));
|
||||
|
||||
learntMobile = preferences.getInt(PREF_LEARNT_MOBILE, INTERVAL);
|
||||
learntWifi = preferences.getInt(PREF_LEARNT_WIFI, INTERVAL);
|
||||
learntOther = preferences.getInt(PREF_LEARNT_OTHER, INTERVAL);
|
||||
}
|
||||
|
||||
public String getNetworkPrefForInfo(NetworkInfo info) {
|
||||
if (info == null) return PREF_NETWORK_OTHER;
|
||||
if (info.isRoaming()) return PREF_NETWORK_ROAMING;
|
||||
switch (info.getType()) {
|
||||
case ConnectivityManager.TYPE_MOBILE:
|
||||
return PREF_NETWORK_MOBILE;
|
||||
case ConnectivityManager.TYPE_WIFI:
|
||||
return PREF_NETWORK_WIFI;
|
||||
default:
|
||||
return PREF_NETWORK_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
public int getHeartbeatMsFor(NetworkInfo info) {
|
||||
return getHeartbeatMsFor(getNetworkPrefForInfo(info));
|
||||
}
|
||||
|
||||
public int getMobileInterval() {
|
||||
return networkMobile;
|
||||
}
|
||||
|
||||
public int getWifiInterval() {
|
||||
return networkWifi;
|
||||
}
|
||||
|
||||
public int getRoamingInterval() {
|
||||
return networkRoaming;
|
||||
}
|
||||
|
||||
public int getOtherInterval() {
|
||||
return networkOther;
|
||||
}
|
||||
|
||||
public void setMobileInterval(int value) {
|
||||
this.networkMobile = value;
|
||||
preferences.edit().putString(PREF_NETWORK_MOBILE, Integer.toString(networkMobile)).apply();
|
||||
}
|
||||
|
||||
public void setWifiInterval(int value) {
|
||||
this.networkWifi = value;
|
||||
preferences.edit().putString(PREF_NETWORK_WIFI, Integer.toString(networkWifi)).apply();
|
||||
}
|
||||
|
||||
public void setRoamingInterval(int value) {
|
||||
this.networkRoaming = value;
|
||||
preferences.edit().putString(PREF_NETWORK_ROAMING, Integer.toString(networkRoaming)).apply();
|
||||
}
|
||||
|
||||
public void setOtherInterval(int value) {
|
||||
this.networkOther = value;
|
||||
preferences.edit().putString(PREF_NETWORK_OTHER, Integer.toString(networkOther)).apply();
|
||||
}
|
||||
|
||||
public int getHeartbeatMsFor(String pref) {
|
||||
if (PREF_NETWORK_ROAMING.equals(pref)) {
|
||||
if (networkRoaming != 0) return networkRoaming * 60000;
|
||||
else return learntMobile;
|
||||
} else if (PREF_NETWORK_MOBILE.equals(pref)) {
|
||||
if (networkMobile != 0) return networkMobile * 60000;
|
||||
else return learntMobile;
|
||||
} else if (PREF_NETWORK_WIFI.equals(pref)) {
|
||||
if (networkWifi != 0) return networkWifi * 60000;
|
||||
else return learntWifi;
|
||||
} else {
|
||||
if (networkOther != 0) return networkOther * 60000;
|
||||
else return learntOther;
|
||||
}
|
||||
}
|
||||
|
||||
public int getNetworkValue(String pref) {
|
||||
switch (pref) {
|
||||
case PREF_NETWORK_MOBILE:
|
||||
return networkMobile;
|
||||
case PREF_NETWORK_ROAMING:
|
||||
return networkRoaming;
|
||||
case PREF_NETWORK_WIFI:
|
||||
return networkWifi;
|
||||
default:
|
||||
return networkOther;
|
||||
}
|
||||
}
|
||||
|
||||
public void learnTimeout(String pref) {
|
||||
Log.d("GmsGcmPrefs", "learnTimeout: " + pref);
|
||||
switch (pref) {
|
||||
case PREF_NETWORK_MOBILE:
|
||||
case PREF_NETWORK_ROAMING:
|
||||
learntMobile *= 0.95;
|
||||
break;
|
||||
case PREF_NETWORK_WIFI:
|
||||
learntWifi *= 0.95;
|
||||
break;
|
||||
default:
|
||||
learntOther *= 0.95;
|
||||
break;
|
||||
}
|
||||
updateLearntValues();
|
||||
}
|
||||
|
||||
public void learnReached(String pref, long time) {
|
||||
Log.d("GmsGcmPrefs", "learnReached: " + pref + " / " + time);
|
||||
switch (pref) {
|
||||
case PREF_NETWORK_MOBILE:
|
||||
case PREF_NETWORK_ROAMING:
|
||||
if (time > learntMobile / 4 * 3)
|
||||
learntMobile *= 1.02;
|
||||
break;
|
||||
case PREF_NETWORK_WIFI:
|
||||
if (time > learntWifi / 4 * 3)
|
||||
learntWifi *= 1.02;
|
||||
break;
|
||||
default:
|
||||
if (time > learntOther / 4 * 3)
|
||||
learntOther *= 1.02;
|
||||
break;
|
||||
}
|
||||
updateLearntValues();
|
||||
}
|
||||
|
||||
private void updateLearntValues() {
|
||||
preferences.edit().putInt(PREF_LEARNT_MOBILE, INTERVAL).putInt(PREF_LEARNT_WIFI, INTERVAL).putInt(PREF_LEARNT_OTHER, INTERVAL).apply();
|
||||
}
|
||||
|
||||
public int getLearntMobileInterval() {
|
||||
return learntMobile;
|
||||
}
|
||||
|
||||
public int getLearntWifiInterval() {
|
||||
return learntWifi;
|
||||
}
|
||||
|
||||
public int getLearntOtherInterval() {
|
||||
return learntOther;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
update();
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return gcmEnabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean value) {
|
||||
boolean changed = gcmEnabled != value;
|
||||
preferences.edit().putBoolean(GcmPrefs.PREF_ENABLE_GCM, value).apply();
|
||||
if (!changed) return;
|
||||
if (!value) {
|
||||
McsService.stop(context);
|
||||
} else {
|
||||
context.sendBroadcast(new Intent(TriggerReceiver.FORCE_TRY_RECONNECT, null, context, TriggerReceiver.class));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabledFor(NetworkInfo info) {
|
||||
return isEnabled() && info != null && getHeartbeatMsFor(info) >= 0;
|
||||
}
|
||||
|
||||
public boolean isGcmLogEnabled() {
|
||||
return gcmLogEnabled;
|
||||
}
|
||||
|
||||
public List<String> getLastPersistedIds() {
|
||||
if (lastPersistedId.isEmpty()) return Collections.emptyList();
|
||||
return Arrays.asList(lastPersistedId.split("\\|"));
|
||||
}
|
||||
|
||||
public void extendLastPersistedId(String id) {
|
||||
if (!lastPersistedId.isEmpty()) lastPersistedId += "|";
|
||||
lastPersistedId += id;
|
||||
preferences.edit().putString(PREF_LAST_PERSISTENT_ID, lastPersistedId).apply();
|
||||
}
|
||||
|
||||
public void clearLastPersistedId() {
|
||||
lastPersistedId = "";
|
||||
preferences.edit().putString(PREF_LAST_PERSISTENT_ID, lastPersistedId).apply();
|
||||
}
|
||||
}
|
@ -73,6 +73,7 @@ import okio.ByteString;
|
||||
|
||||
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static org.microg.gms.common.PackageUtils.warnIfNotPersistentProcess;
|
||||
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_RECEIVE;
|
||||
import static org.microg.gms.gcm.GcmConstants.EXTRA_APP;
|
||||
import static org.microg.gms.gcm.GcmConstants.EXTRA_APP_OVERRIDE;
|
||||
@ -234,6 +235,7 @@ public class McsService extends Service implements Handler.Callback {
|
||||
}
|
||||
|
||||
public synchronized static boolean isConnected(Context context) {
|
||||
warnIfNotPersistentProcess(McsService.class);
|
||||
if (inputStream == null || !inputStream.isAlive() || outputStream == null || !outputStream.isAlive()) {
|
||||
logd(null, "Connection is not enabled or dead.");
|
||||
return false;
|
||||
@ -244,13 +246,14 @@ public class McsService extends Service implements Handler.Callback {
|
||||
closeAll();
|
||||
} else if (SystemClock.elapsedRealtime() - lastHeartbeatAckElapsedRealtime > 2 * heartbeatMs) {
|
||||
logd(null, "No heartbeat for " + (SystemClock.elapsedRealtime() - lastHeartbeatAckElapsedRealtime) / 1000 + " seconds, connection assumed to be dead after " + 2 * heartbeatMs / 1000 + " seconds");
|
||||
GcmPrefs.get(context).learnTimeout(activeNetworkPref);
|
||||
GcmPrefs.get(context).learnTimeout(context, activeNetworkPref);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static long getStartTimestamp() {
|
||||
warnIfNotPersistentProcess(McsService.class);
|
||||
return startTimestamp;
|
||||
}
|
||||
|
||||
@ -460,7 +463,7 @@ public class McsService extends Service implements Handler.Callback {
|
||||
|
||||
private void handleLoginResponse(LoginResponse loginResponse) {
|
||||
if (loginResponse.error == null) {
|
||||
GcmPrefs.get(this).clearLastPersistedId();
|
||||
GcmPrefs.clearLastPersistedId(this);
|
||||
logd(this, "Logged in");
|
||||
wakeLock.release();
|
||||
} else {
|
||||
@ -470,7 +473,7 @@ public class McsService extends Service implements Handler.Callback {
|
||||
|
||||
private void handleCloudMessage(DataMessageStanza message) {
|
||||
if (message.persistent_id != null) {
|
||||
GcmPrefs.get(this).extendLastPersistedId(message.persistent_id);
|
||||
GcmPrefs.get(this).extendLastPersistedId(this, message.persistent_id);
|
||||
}
|
||||
if (SELF_CATEGORY.equals(message.category)) {
|
||||
handleSelfMessage(message);
|
||||
@ -488,7 +491,7 @@ public class McsService extends Service implements Handler.Callback {
|
||||
}
|
||||
|
||||
private void handleHeartbeatAck(HeartbeatAck ack) {
|
||||
GcmPrefs.get(this).learnReached(activeNetworkPref, SystemClock.elapsedRealtime() - lastIncomingNetworkRealtime);
|
||||
GcmPrefs.get(this).learnReached(this, activeNetworkPref, SystemClock.elapsedRealtime() - lastIncomingNetworkRealtime);
|
||||
lastHeartbeatAckElapsedRealtime = SystemClock.elapsedRealtime();
|
||||
wakeLock.release();
|
||||
}
|
||||
@ -498,13 +501,13 @@ public class McsService extends Service implements Handler.Callback {
|
||||
return new LoginRequest.Builder()
|
||||
.adaptive_heartbeat(false)
|
||||
.auth_service(LoginRequest.AuthService.ANDROID_ID)
|
||||
.auth_token(Long.toString(info.securityToken))
|
||||
.auth_token(Long.toString(info.getSecurityToken()))
|
||||
.id("android-" + SDK_INT)
|
||||
.domain("mcs.android.com")
|
||||
.device_id("android-" + Long.toHexString(info.androidId))
|
||||
.device_id("android-" + Long.toHexString(info.getAndroidId()))
|
||||
.network_type(1)
|
||||
.resource(Long.toString(info.androidId))
|
||||
.user(Long.toString(info.androidId))
|
||||
.resource(Long.toString(info.getAndroidId()))
|
||||
.user(Long.toString(info.getAndroidId()))
|
||||
.use_rmq2(true)
|
||||
.setting(Collections.singletonList(new Setting.Builder().name("new_vc").value("1").build()))
|
||||
.received_persistent_id(GcmPrefs.get(this).getLastPersistedIds())
|
||||
|
@ -87,7 +87,7 @@ public class PushRegisterManager {
|
||||
if (!request.delete) {
|
||||
if (!prefs.isEnabled() ||
|
||||
(app != null && !app.allowRegister) ||
|
||||
LastCheckinInfo.read(context).lastCheckin <= 0) {
|
||||
LastCheckinInfo.read(context).getLastCheckin() <= 0) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EXTRA_ERROR, ERROR_SERVICE_NOT_AVAILABLE);
|
||||
callback.onResult(bundle);
|
||||
|
@ -70,8 +70,8 @@ public class RegisterRequest extends HttpFormClient.Request {
|
||||
}
|
||||
|
||||
public RegisterRequest checkin(LastCheckinInfo lastCheckinInfo) {
|
||||
androidId = lastCheckinInfo.androidId;
|
||||
securityToken = lastCheckinInfo.securityToken;
|
||||
androidId = lastCheckinInfo.getAndroidId();
|
||||
securityToken = lastCheckinInfo.getSecurityToken();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ public class TriggerReceiver extends WakefulBroadcastReceiver {
|
||||
McsService.resetCurrentDelay();
|
||||
}
|
||||
|
||||
if (LastCheckinInfo.read(context).androidId == 0) {
|
||||
if (LastCheckinInfo.read(context).getAndroidId() == 0) {
|
||||
Log.d(TAG, "Ignoring " + intent + ": need to checkin first.");
|
||||
return;
|
||||
}
|
||||
|
@ -55,14 +55,6 @@ public class GServicesProvider extends ContentProvider {
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
if (CheckinPrefs.get(getContext()).isEnabled()) {
|
||||
getContext().sendOrderedBroadcast(new Intent(getContext(), org.microg.gms.checkin.TriggerReceiver.class), null);
|
||||
|
||||
if (GcmPrefs.get(getContext()).isEnabled()) {
|
||||
getContext().sendBroadcast(new Intent(org.microg.gms.gcm.TriggerReceiver.FORCE_TRY_RECONNECT, null, getContext(), org.microg.gms.gcm.TriggerReceiver.class));
|
||||
}
|
||||
}
|
||||
|
||||
databaseHelper = new DatabaseHelper(getContext());
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
package org.microg.gms.auth
|
||||
|
||||
import android.content.Context
|
||||
import org.microg.gms.settings.SettingsContract
|
||||
import org.microg.gms.settings.SettingsContract.Auth
|
||||
|
||||
object AuthPrefs {
|
||||
|
||||
@JvmStatic
|
||||
fun isTrustGooglePermitted(context: Context): Boolean {
|
||||
return SettingsContract.getSettings(context, Auth.CONTENT_URI, arrayOf(Auth.TRUST_GOOGLE)) { c ->
|
||||
c.getInt(0) != 0
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isAuthVisible(context: Context): Boolean {
|
||||
return SettingsContract.getSettings(context, Auth.CONTENT_URI, arrayOf(Auth.VISIBLE)) { c ->
|
||||
c.getInt(0) != 0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.microg.gms.checkin
|
||||
|
||||
import android.content.Context
|
||||
import org.microg.gms.settings.SettingsContract
|
||||
import org.microg.gms.settings.SettingsContract.CheckIn
|
||||
|
||||
object CheckinPrefs {
|
||||
|
||||
@JvmStatic
|
||||
fun isEnabled(context: Context): Boolean {
|
||||
val projection = arrayOf(CheckIn.ENABLED)
|
||||
return SettingsContract.getSettings(context, CheckIn.CONTENT_URI, projection) { c ->
|
||||
c.getInt(0) != 0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2017 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.microg.gms.checkin
|
||||
|
||||
import android.content.Context
|
||||
import org.microg.gms.settings.SettingsContract
|
||||
import org.microg.gms.settings.SettingsContract.CheckIn
|
||||
|
||||
data class LastCheckinInfo(
|
||||
val lastCheckin: Long,
|
||||
val androidId: Long,
|
||||
val securityToken: Long,
|
||||
val digest: String,
|
||||
val versionInfo: String,
|
||||
val deviceDataVersionInfo: String,
|
||||
) {
|
||||
|
||||
constructor(r: CheckinResponse) : this(
|
||||
lastCheckin = r.timeMs ?: 0L,
|
||||
androidId = r.androidId ?: 0L,
|
||||
securityToken = r.securityToken ?: 0L,
|
||||
digest = r.digest ?: CheckIn.INITIAL_DIGEST,
|
||||
versionInfo = r.versionInfo ?: "",
|
||||
deviceDataVersionInfo = r.deviceDataVersionInfo ?: "",
|
||||
)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun read(context: Context): LastCheckinInfo {
|
||||
val projection = arrayOf(
|
||||
CheckIn.ANDROID_ID,
|
||||
CheckIn.DIGEST,
|
||||
CheckIn.LAST_CHECK_IN,
|
||||
CheckIn.SECURITY_TOKEN,
|
||||
CheckIn.VERSION_INFO,
|
||||
CheckIn.DEVICE_DATA_VERSION_INFO,
|
||||
)
|
||||
return SettingsContract.getSettings(context, CheckIn.CONTENT_URI, projection) { c ->
|
||||
LastCheckinInfo(
|
||||
androidId = c.getLong(0),
|
||||
digest = c.getString(1),
|
||||
lastCheckin = c.getLong(2),
|
||||
securityToken = c.getLong(3),
|
||||
versionInfo = c.getString(4),
|
||||
deviceDataVersionInfo = c.getString(5),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun clear(context: Context) = SettingsContract.setSettings(context, CheckIn.CONTENT_URI) {
|
||||
put(CheckIn.ANDROID_ID, 0L)
|
||||
put(CheckIn.DIGEST, CheckIn.INITIAL_DIGEST)
|
||||
put(CheckIn.LAST_CHECK_IN, 0L)
|
||||
put(CheckIn.SECURITY_TOKEN, 0L)
|
||||
put(CheckIn.VERSION_INFO, "")
|
||||
put(CheckIn.DEVICE_DATA_VERSION_INFO, "")
|
||||
}
|
||||
}
|
||||
|
||||
fun write(context: Context) = SettingsContract.setSettings(context, CheckIn.CONTENT_URI) {
|
||||
put(CheckIn.ANDROID_ID, androidId)
|
||||
put(CheckIn.DIGEST, digest)
|
||||
put(CheckIn.LAST_CHECK_IN, lastCheckin)
|
||||
put(CheckIn.SECURITY_TOKEN, securityToken)
|
||||
put(CheckIn.VERSION_INFO, versionInfo)
|
||||
put(CheckIn.DEVICE_DATA_VERSION_INFO, deviceDataVersionInfo)
|
||||
}
|
||||
}
|
@ -5,89 +5,38 @@
|
||||
|
||||
package org.microg.gms.checkin
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.microg.gms.settings.SettingsContract.CheckIn
|
||||
import org.microg.gms.settings.SettingsContract.getSettings
|
||||
import org.microg.gms.settings.SettingsContract.setSettings
|
||||
import java.io.Serializable
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
private const val ACTION_SERVICE_INFO_REQUEST = "org.microg.gms.checkin.SERVICE_INFO_REQUEST"
|
||||
private const val ACTION_UPDATE_CONFIGURATION = "org.microg.gms.checkin.UPDATE_CONFIGURATION"
|
||||
private const val ACTION_SERVICE_INFO_RESPONSE = "org.microg.gms.checkin.SERVICE_INFO_RESPONSE"
|
||||
private const val EXTRA_SERVICE_INFO = "org.microg.gms.checkin.SERVICE_INFO"
|
||||
private const val EXTRA_CONFIGURATION = "org.microg.gms.checkin.CONFIGURATION"
|
||||
private const val TAG = "GmsCheckinStatusInfo"
|
||||
|
||||
data class ServiceInfo(val configuration: ServiceConfiguration, val lastCheckin: Long, val androidId: Long) : Serializable
|
||||
|
||||
data class ServiceConfiguration(val enabled: Boolean) : Serializable {
|
||||
fun saveToPrefs(context: Context) {
|
||||
CheckinPrefs.setEnabled(context, enabled)
|
||||
data class ServiceConfiguration(val enabled: Boolean) : Serializable
|
||||
|
||||
suspend fun getCheckinServiceInfo(context: Context): ServiceInfo = withContext(Dispatchers.IO) {
|
||||
val projection = arrayOf(CheckIn.ENABLED, CheckIn.LAST_CHECK_IN, CheckIn.ANDROID_ID)
|
||||
getSettings(context, CheckIn.CONTENT_URI, projection) { c ->
|
||||
ServiceInfo(
|
||||
configuration = ServiceConfiguration(c.getInt(0) != 0),
|
||||
lastCheckin = c.getLong(1),
|
||||
androidId = c.getLong(2),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private 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)
|
||||
suspend fun setCheckinServiceConfiguration(context: Context, configuration: ServiceConfiguration) = withContext(Dispatchers.IO) {
|
||||
val serviceInfo = getCheckinServiceInfo(context)
|
||||
if (serviceInfo.configuration == configuration) return@withContext
|
||||
// enabled state is not already set, setting it now
|
||||
setSettings(context, CheckIn.CONTENT_URI) {
|
||||
put(CheckIn.ENABLED, configuration.enabled)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
if (configuration.enabled) {
|
||||
context.sendOrderedBroadcast(Intent(context, TriggerReceiver::class.java), null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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,97 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020, microG Project Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.microg.gms.fonts
|
||||
|
||||
import android.content.ContentProvider
|
||||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.database.MatrixCursor
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.os.ParcelFileDescriptor.MODE_READ_ONLY
|
||||
import android.util.Log
|
||||
import java.io.File
|
||||
|
||||
class FontsProvider : ContentProvider() {
|
||||
|
||||
override fun onCreate(): Boolean {
|
||||
Log.d(TAG, "onCreate")
|
||||
return true
|
||||
}
|
||||
|
||||
override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
|
||||
Log.d(TAG, "call $method $arg $extras")
|
||||
return null
|
||||
}
|
||||
|
||||
override fun query(
|
||||
uri: Uri,
|
||||
projection: Array<out String>?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<out String>?,
|
||||
sortOrder: String?
|
||||
): Cursor {
|
||||
Log.e(TAG, "query: $uri ${projection?.toList()} $selection")
|
||||
val cursor = MatrixCursor(COLUMNS)
|
||||
// We could also return an empty cursor here, but some apps have been reported to crash
|
||||
// when their expected font is not returned by Google's font provider.
|
||||
cursor.addRow(
|
||||
arrayOf(
|
||||
1337L, // file_id
|
||||
0, // font_ttc_index
|
||||
null, // font_variation_settings
|
||||
400, // font_weight
|
||||
0, // font_italic
|
||||
0, // result_code: RESULT_CODE_OK
|
||||
)
|
||||
)
|
||||
return cursor
|
||||
}
|
||||
|
||||
override fun insert(uri: Uri, values: ContentValues?): Uri {
|
||||
Log.d(TAG, "insert: $uri, $values")
|
||||
return uri
|
||||
}
|
||||
|
||||
override fun update(
|
||||
uri: Uri,
|
||||
values: ContentValues?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<out String>?
|
||||
): Int {
|
||||
Log.d(TAG, "update: $uri, $values, $selection, $selectionArgs")
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
|
||||
Log.d(TAG, "delete: $uri, $selection, $selectionArgs")
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun getType(uri: Uri): String {
|
||||
Log.d(TAG, "getType: $uri")
|
||||
return "font/ttf"
|
||||
}
|
||||
|
||||
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
|
||||
Log.d(TAG, "openFile: $uri mode: $mode")
|
||||
val file = File("/system/fonts/Roboto-Regular.ttf")
|
||||
return ParcelFileDescriptor.open(file, MODE_READ_ONLY)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "FontsProvider"
|
||||
private val COLUMNS = arrayOf(
|
||||
"file_id",
|
||||
"font_ttc_index",
|
||||
"font_variation_settings",
|
||||
"font_weight",
|
||||
"font_italic",
|
||||
"result_code"
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
package org.microg.gms.gcm
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.*
|
||||
import android.util.Log
|
||||
import org.microg.gms.gcm.TriggerReceiver.FORCE_TRY_RECONNECT
|
||||
import org.microg.gms.settings.SettingsContract
|
||||
import org.microg.gms.settings.SettingsContract.Gcm
|
||||
import org.microg.gms.settings.SettingsContract.setSettings
|
||||
|
||||
@Suppress("Warnings")
|
||||
data class GcmPrefs(
|
||||
val isGcmLogEnabled: Boolean,
|
||||
val lastPersistedId: String?,
|
||||
val gcmEnabled: Boolean,
|
||||
val networkMobile: Int,
|
||||
val networkWifi: Int,
|
||||
val networkRoaming: Int,
|
||||
val networkOther: Int,
|
||||
val learntMobileInterval: Int,
|
||||
val learntWifiInterval: Int,
|
||||
val learntOtherInterval: Int,
|
||||
) {
|
||||
|
||||
val isEnabled: Boolean get() = gcmEnabled
|
||||
|
||||
val lastPersistedIds: List<String>
|
||||
get() = if (lastPersistedId.isNullOrEmpty()) emptyList() else lastPersistedId.split("\\|")
|
||||
|
||||
companion object {
|
||||
const val PREF_NETWORK_MOBILE = Gcm.NETWORK_MOBILE
|
||||
const val PREF_NETWORK_WIFI = Gcm.NETWORK_WIFI
|
||||
const val PREF_NETWORK_ROAMING = Gcm.NETWORK_ROAMING
|
||||
const val PREF_NETWORK_OTHER = Gcm.NETWORK_OTHER
|
||||
|
||||
private const val INTERVAL = 1 * 60 * 1000 // 1 minute
|
||||
|
||||
@JvmStatic
|
||||
fun get(context: Context): GcmPrefs {
|
||||
return SettingsContract.getSettings(context, Gcm.CONTENT_URI, Gcm.PROJECTION) { c ->
|
||||
GcmPrefs(
|
||||
isGcmLogEnabled = c.getInt(0) != 0,
|
||||
lastPersistedId = c.getString(1),
|
||||
gcmEnabled = c.getInt(3) != 0,
|
||||
networkMobile = c.getInt(4),
|
||||
networkWifi = c.getInt(5),
|
||||
networkRoaming = c.getInt(6),
|
||||
networkOther = c.getInt(7),
|
||||
learntMobileInterval = c.getInt(8),
|
||||
learntWifiInterval = c.getInt(9),
|
||||
learntOtherInterval = c.getInt(10),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun write(context: Context, config: ServiceConfiguration) {
|
||||
val gcmPrefs = get(context)
|
||||
setSettings(context, Gcm.CONTENT_URI) {
|
||||
put(Gcm.ENABLE_GCM, config.enabled)
|
||||
put(Gcm.NETWORK_MOBILE, config.mobile)
|
||||
put(Gcm.NETWORK_WIFI, config.wifi)
|
||||
put(Gcm.NETWORK_ROAMING, config.roaming)
|
||||
put(Gcm.NETWORK_OTHER, config.other)
|
||||
}
|
||||
gcmPrefs.setEnabled(context, config.enabled)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun clearLastPersistedId(context: Context) {
|
||||
setSettings(context, Gcm.CONTENT_URI) {
|
||||
put(Gcm.LAST_PERSISTENT_ID, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this whenever the enabled state of GCM has changed.
|
||||
*/
|
||||
private fun setEnabled(context: Context, enabled: Boolean) {
|
||||
if (gcmEnabled == enabled) return
|
||||
if (enabled) {
|
||||
val i = Intent(FORCE_TRY_RECONNECT, null, context, TriggerReceiver::class.java)
|
||||
context.sendBroadcast(i)
|
||||
} else {
|
||||
McsService.stop(context)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun getNetworkPrefForInfo(info: NetworkInfo?): String {
|
||||
if (info == null) return PREF_NETWORK_OTHER
|
||||
return if (info.isRoaming) PREF_NETWORK_ROAMING else when (info.type) {
|
||||
ConnectivityManager.TYPE_MOBILE -> PREF_NETWORK_MOBILE
|
||||
ConnectivityManager.TYPE_WIFI -> PREF_NETWORK_WIFI
|
||||
else -> PREF_NETWORK_OTHER
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun getHeartbeatMsFor(info: NetworkInfo?): Int {
|
||||
return getHeartbeatMsFor(getNetworkPrefForInfo(info))
|
||||
}
|
||||
|
||||
fun getHeartbeatMsFor(pref: String): Int {
|
||||
return if (PREF_NETWORK_ROAMING == pref) {
|
||||
if (networkRoaming != 0) networkRoaming * 60000 else learntMobileInterval
|
||||
} else if (PREF_NETWORK_MOBILE == pref) {
|
||||
if (networkMobile != 0) networkMobile * 60000 else learntMobileInterval
|
||||
} else if (PREF_NETWORK_WIFI == pref) {
|
||||
if (networkWifi != 0) networkWifi * 60000 else learntWifiInterval
|
||||
} else {
|
||||
if (networkOther != 0) networkOther * 60000 else learntOtherInterval
|
||||
}
|
||||
}
|
||||
|
||||
fun learnTimeout(context: Context, pref: String) {
|
||||
Log.d("GmsGcmPrefs", "learnTimeout: $pref")
|
||||
when (pref) {
|
||||
PREF_NETWORK_MOBILE, PREF_NETWORK_ROAMING -> setSettings(context, Gcm.CONTENT_URI) {
|
||||
put(Gcm.LEARNT_MOBILE, (learntMobileInterval * 0.95).toInt())
|
||||
}
|
||||
PREF_NETWORK_WIFI -> setSettings(context, Gcm.CONTENT_URI) {
|
||||
put(Gcm.LEARNT_WIFI, (learntWifiInterval * 0.95).toInt())
|
||||
}
|
||||
else -> setSettings(context, Gcm.CONTENT_URI) {
|
||||
put(Gcm.LEARNT_OTHER, (learntOtherInterval * 0.95).toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun learnReached(context: Context, pref: String, time: Long) {
|
||||
Log.d("GmsGcmPrefs", "learnReached: $pref / $time")
|
||||
when (pref) {
|
||||
PREF_NETWORK_MOBILE, PREF_NETWORK_ROAMING -> {
|
||||
if (time > learntMobileInterval / 4 * 3) {
|
||||
setSettings(context, Gcm.CONTENT_URI) {
|
||||
put(Gcm.LEARNT_MOBILE, INTERVAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
PREF_NETWORK_WIFI -> {
|
||||
if (time > learntWifiInterval / 4 * 3) {
|
||||
setSettings(context, Gcm.CONTENT_URI) {
|
||||
put(Gcm.LEARNT_WIFI, INTERVAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
if (time > learntOtherInterval / 4 * 3) {
|
||||
setSettings(context, Gcm.CONTENT_URI) {
|
||||
put(Gcm.LEARNT_OTHER, INTERVAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun isEnabledFor(info: NetworkInfo?): Boolean {
|
||||
return isEnabled && info != null && getHeartbeatMsFor(info) >= 0
|
||||
}
|
||||
|
||||
fun extendLastPersistedId(context: Context, id: String) {
|
||||
val newId = if (lastPersistedId.isNullOrEmpty()) id else "$lastPersistedId|$id"
|
||||
setSettings(context, Gcm.CONTENT_URI) {
|
||||
put(Gcm.LAST_PERSISTENT_ID, newId)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -31,7 +31,7 @@ import kotlin.coroutines.suspendCoroutine
|
||||
private const val TAG = "GmsGcmRegister"
|
||||
|
||||
private suspend fun ensureCheckinIsUpToDate(context: Context) {
|
||||
if (!CheckinPrefs.get(context).isEnabled) throw RuntimeException("Checkin disabled")
|
||||
if (!CheckinPrefs.isEnabled(context)) throw RuntimeException("Checkin disabled")
|
||||
val lastCheckin = LastCheckinInfo.read(context).lastCheckin
|
||||
if (lastCheckin < System.currentTimeMillis() - CheckinService.MAX_VALID_CHECKIN_AGE) {
|
||||
val resultData: Bundle = suspendCoroutine { continuation ->
|
||||
|
@ -10,52 +10,40 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.Serializable
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
private const val ACTION_SERVICE_INFO_REQUEST = "org.microg.gms.gcm.SERVICE_INFO_REQUEST"
|
||||
private const val ACTION_UPDATE_CONFIGURATION = "org.microg.gms.gcm.UPDATE_CONFIGURATION"
|
||||
private const val ACTION_SERVICE_INFO_RESPONSE = "org.microg.gms.gcm.SERVICE_INFO_RESPONSE"
|
||||
private const val EXTRA_SERVICE_INFO = "org.microg.gms.gcm.SERVICE_INFO"
|
||||
private const val EXTRA_CONFIGURATION = "org.microg.gms.gcm.CONFIGURATION"
|
||||
private const val TAG = "GmsGcmStatusInfo"
|
||||
|
||||
data class ServiceInfo(val configuration: ServiceConfiguration, val connected: Boolean, val startTimestamp: Long, val learntMobileInterval: Int, val learntWifiInterval: Int, val learntOtherInterval: Int) : Serializable
|
||||
|
||||
// TODO: Intervals
|
||||
data class ServiceConfiguration(val enabled: Boolean, val mobile: Int, val wifi: Int, val roaming: Int, val other: Int) : Serializable {
|
||||
fun saveToPrefs(context: Context) {
|
||||
GcmPrefs.get(context).apply {
|
||||
isEnabled = enabled
|
||||
mobileInterval = mobile
|
||||
wifiInterval = wifi
|
||||
roamingInterval = roaming
|
||||
otherInterval = other
|
||||
}
|
||||
}
|
||||
}
|
||||
data class ServiceConfiguration(val enabled: Boolean, val mobile: Int, val wifi: Int, val roaming: Int, val other: Int) : Serializable
|
||||
|
||||
private fun GcmPrefs.toConfiguration(): ServiceConfiguration = ServiceConfiguration(isEnabled, mobileInterval, wifiInterval, roamingInterval, otherInterval)
|
||||
private fun GcmPrefs.toConfiguration(): ServiceConfiguration = ServiceConfiguration(isEnabled, networkMobile, networkWifi, networkRoaming, networkOther)
|
||||
|
||||
class ServiceInfoReceiver : BroadcastReceiver() {
|
||||
private fun sendInfoResponse(context: Context) {
|
||||
context.sendOrderedBroadcast(Intent(ACTION_SERVICE_INFO_RESPONSE).apply {
|
||||
setPackage(context.packageName)
|
||||
val prefs = GcmPrefs.get(context)
|
||||
putExtra(EXTRA_SERVICE_INFO, ServiceInfo(prefs.toConfiguration(), McsService.isConnected(context), McsService.getStartTimestamp(), prefs.learntMobileInterval, prefs.learntWifiInterval, prefs.learntOtherInterval))
|
||||
}, null)
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
try {
|
||||
when (intent.action) {
|
||||
ACTION_UPDATE_CONFIGURATION -> {
|
||||
(intent.getSerializableExtra(EXTRA_CONFIGURATION) as? ServiceConfiguration)?.saveToPrefs(context)
|
||||
}
|
||||
}
|
||||
sendInfoResponse(context)
|
||||
context.sendOrderedBroadcast(Intent(ACTION_SERVICE_INFO_RESPONSE).apply {
|
||||
setPackage(context.packageName)
|
||||
val prefs = GcmPrefs.get(context)
|
||||
val info = ServiceInfo(
|
||||
configuration = prefs.toConfiguration(),
|
||||
connected = McsService.isConnected(context),
|
||||
startTimestamp = McsService.getStartTimestamp(),
|
||||
learntMobileInterval = prefs.learntMobileInterval,
|
||||
learntWifiInterval = prefs.learntWifiInterval,
|
||||
learntOtherInterval = prefs.learntOtherInterval
|
||||
)
|
||||
putExtra(EXTRA_SERVICE_INFO, info)
|
||||
}, null)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, e)
|
||||
}
|
||||
@ -87,12 +75,11 @@ private suspend fun sendToServiceInfoReceiver(intent: Intent, context: Context):
|
||||
}
|
||||
|
||||
suspend fun getGcmServiceInfo(context: Context): ServiceInfo = sendToServiceInfoReceiver(
|
||||
// this is still using a broadcast, because it calls into McsService in the persistent process
|
||||
Intent(context, ServiceInfoReceiver::class.java).apply {
|
||||
action = ACTION_SERVICE_INFO_REQUEST
|
||||
}, context)
|
||||
|
||||
suspend fun setGcmServiceConfiguration(context: Context, configuration: ServiceConfiguration): ServiceInfo = sendToServiceInfoReceiver(
|
||||
Intent(context, ServiceInfoReceiver::class.java).apply {
|
||||
action = ACTION_UPDATE_CONFIGURATION
|
||||
putExtra(EXTRA_CONFIGURATION, configuration)
|
||||
}, context)
|
||||
suspend fun setGcmServiceConfiguration(context: Context, configuration: ServiceConfiguration) = withContext(Dispatchers.IO) {
|
||||
GcmPrefs.write(context, configuration)
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package org.microg.gms.settings
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
|
||||
object SettingsContract {
|
||||
const val AUTHORITY = "org.microg.gms.settings"
|
||||
val AUTHORITY_URI: Uri = Uri.parse("content://$AUTHORITY")
|
||||
|
||||
object CheckIn {
|
||||
private const val id = "check-in"
|
||||
val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id)
|
||||
const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id"
|
||||
|
||||
const val ENABLED = "checkin_enable_service"
|
||||
const val ANDROID_ID = "androidId"
|
||||
const val DIGEST = "digest"
|
||||
const val LAST_CHECK_IN = "lastCheckin"
|
||||
const val SECURITY_TOKEN = "securityToken"
|
||||
const val VERSION_INFO = "versionInfo"
|
||||
const val DEVICE_DATA_VERSION_INFO = "deviceDataVersionInfo"
|
||||
|
||||
val PROJECTION = arrayOf(
|
||||
ENABLED,
|
||||
ANDROID_ID,
|
||||
DIGEST,
|
||||
LAST_CHECK_IN,
|
||||
SECURITY_TOKEN,
|
||||
VERSION_INFO,
|
||||
DEVICE_DATA_VERSION_INFO,
|
||||
)
|
||||
const val PREFERENCES_NAME = "checkin"
|
||||
const val INITIAL_DIGEST = "1-929a0dca0eee55513280171a8585da7dcd3700f8"
|
||||
}
|
||||
|
||||
object Gcm {
|
||||
private const val id = "gcm"
|
||||
val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id)
|
||||
const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id"
|
||||
|
||||
const val FULL_LOG = "gcm_full_log"
|
||||
const val LAST_PERSISTENT_ID = "gcm_last_persistent_id"
|
||||
const val ENABLE_GCM = "gcm_enable_mcs_service"
|
||||
|
||||
const val NETWORK_MOBILE = "gcm_network_mobile"
|
||||
const val NETWORK_WIFI = "gcm_network_wifi"
|
||||
const val NETWORK_ROAMING = "gcm_network_roaming"
|
||||
const val NETWORK_OTHER = "gcm_network_other"
|
||||
|
||||
const val LEARNT_MOBILE = "gcm_learnt_mobile"
|
||||
const val LEARNT_WIFI = "gcm_learnt_wifi"
|
||||
const val LEARNT_OTHER = "gcm_learnt_other"
|
||||
|
||||
val PROJECTION = arrayOf(
|
||||
FULL_LOG,
|
||||
LAST_PERSISTENT_ID,
|
||||
ENABLE_GCM,
|
||||
NETWORK_MOBILE,
|
||||
NETWORK_WIFI,
|
||||
NETWORK_ROAMING,
|
||||
NETWORK_OTHER,
|
||||
LEARNT_MOBILE,
|
||||
LEARNT_WIFI,
|
||||
LEARNT_OTHER,
|
||||
)
|
||||
}
|
||||
|
||||
object Auth {
|
||||
private const val id = "auth"
|
||||
val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id)
|
||||
const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id"
|
||||
|
||||
const val TRUST_GOOGLE = "auth_manager_trust_google"
|
||||
const val VISIBLE = "auth_manager_visible"
|
||||
|
||||
val PROJECTION = arrayOf(
|
||||
TRUST_GOOGLE,
|
||||
VISIBLE,
|
||||
)
|
||||
}
|
||||
|
||||
fun <T> getSettings(context: Context, uri: Uri, projection: Array<out String>?, f: (Cursor) -> T): T {
|
||||
context.contentResolver.query(uri, projection, null, null, null).use { c ->
|
||||
require(c != null) { "Cursor for query $uri ${projection?.toList()} was null" }
|
||||
if (!c.moveToFirst()) error("Cursor for query $uri ${projection?.toList()} was empty")
|
||||
return f.invoke(c)
|
||||
}
|
||||
}
|
||||
|
||||
fun setSettings(context: Context, uri: Uri, v: ContentValues.() -> Unit) {
|
||||
val values = ContentValues().apply { v.invoke(this) }
|
||||
val affected = context.contentResolver.update(uri, values, null, null)
|
||||
require(affected == 1) { "Update for $uri with $values affected 0 rows"}
|
||||
}
|
||||
}
|
@ -0,0 +1,228 @@
|
||||
package org.microg.gms.settings
|
||||
|
||||
import android.content.ContentProvider
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Context.MODE_PRIVATE
|
||||
import android.content.SharedPreferences
|
||||
import android.database.Cursor
|
||||
import android.database.MatrixCursor
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.preference.PreferenceManager
|
||||
import org.microg.gms.common.PackageUtils.warnIfNotMainProcess
|
||||
import org.microg.gms.settings.SettingsContract.AUTHORITY
|
||||
import org.microg.gms.settings.SettingsContract.Auth
|
||||
import org.microg.gms.settings.SettingsContract.CheckIn
|
||||
import org.microg.gms.settings.SettingsContract.Gcm
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* All settings access should go through this [ContentProvider],
|
||||
* because it provides safe access from different processes which normal [SharedPreferences] don't.
|
||||
*/
|
||||
class SettingsProvider : ContentProvider() {
|
||||
|
||||
private val preferences: SharedPreferences by lazy {
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
}
|
||||
private val checkInPrefs by lazy {
|
||||
context!!.getSharedPreferences(CheckIn.PREFERENCES_NAME, MODE_PRIVATE)
|
||||
}
|
||||
private val systemDefaultPreferences: SharedPreferences? by lazy {
|
||||
try {
|
||||
Context::class.java.getDeclaredMethod(
|
||||
"getSharedPreferences",
|
||||
File::class.java,
|
||||
Int::class.javaPrimitiveType
|
||||
).invoke(context, File("/system/etc/microg.xml"), MODE_PRIVATE) as SharedPreferences
|
||||
} catch (ignored: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun query(
|
||||
uri: Uri,
|
||||
projection: Array<out String>?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<out String>?,
|
||||
sortOrder: String?
|
||||
): Cursor? = when (uri) {
|
||||
CheckIn.CONTENT_URI -> queryCheckIn(projection ?: CheckIn.PROJECTION)
|
||||
Gcm.CONTENT_URI -> queryGcm(projection ?: Gcm.PROJECTION)
|
||||
Auth.CONTENT_URI -> queryAuth(projection ?: Auth.PROJECTION)
|
||||
else -> null
|
||||
}
|
||||
|
||||
override fun update(
|
||||
uri: Uri,
|
||||
values: ContentValues?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<out String>?
|
||||
): Int {
|
||||
warnIfNotMainProcess(context, this.javaClass)
|
||||
if (values == null) return 0
|
||||
when (uri) {
|
||||
CheckIn.CONTENT_URI -> updateCheckIn(values)
|
||||
Gcm.CONTENT_URI -> updateGcm(values)
|
||||
Auth.CONTENT_URI -> updateAuth(values)
|
||||
else -> return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
private fun queryCheckIn(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
|
||||
when (key) {
|
||||
CheckIn.ENABLED -> getSettingsBoolean(key, true)
|
||||
CheckIn.ANDROID_ID -> checkInPrefs.getLong(key, 0)
|
||||
CheckIn.DIGEST -> checkInPrefs.getString(key, CheckIn.INITIAL_DIGEST)
|
||||
?: CheckIn.INITIAL_DIGEST
|
||||
CheckIn.LAST_CHECK_IN -> checkInPrefs.getLong(key, 0)
|
||||
CheckIn.SECURITY_TOKEN -> checkInPrefs.getLong(key, 0)
|
||||
CheckIn.VERSION_INFO -> checkInPrefs.getString(key, "") ?: ""
|
||||
CheckIn.DEVICE_DATA_VERSION_INFO -> checkInPrefs.getString(key, "") ?: ""
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCheckIn(values: ContentValues) {
|
||||
if (values.size() == 0) return
|
||||
if (values.size() == 1 && values.containsKey(CheckIn.ENABLED)) {
|
||||
// special case: only changing enabled state
|
||||
updateCheckInEnabled(values.getAsBoolean(CheckIn.ENABLED))
|
||||
return
|
||||
}
|
||||
val editor = checkInPrefs.edit()
|
||||
values.valueSet().forEach { (key, value) ->
|
||||
// TODO remove log
|
||||
Log.e("TEST", "check-in update: $key = $value")
|
||||
if (key == CheckIn.ENABLED) {
|
||||
// special case: not saved in checkInPrefs
|
||||
updateCheckInEnabled(value as Boolean)
|
||||
}
|
||||
when (key) {
|
||||
CheckIn.ANDROID_ID -> editor.putLong(key, value as Long)
|
||||
CheckIn.DIGEST -> editor.putString(key, value as String?)
|
||||
CheckIn.LAST_CHECK_IN -> editor.putLong(key, value as Long)
|
||||
CheckIn.SECURITY_TOKEN -> editor.putLong(key, value as Long)
|
||||
CheckIn.VERSION_INFO -> editor.putString(key, value as String?)
|
||||
CheckIn.DEVICE_DATA_VERSION_INFO -> editor.putString(key, value as String?)
|
||||
}
|
||||
}
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
private fun updateCheckInEnabled(enabled: Boolean) {
|
||||
preferences.edit()
|
||||
.putBoolean(CheckIn.ENABLED, enabled)
|
||||
.apply()
|
||||
}
|
||||
|
||||
private fun queryGcm(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
|
||||
when (key) {
|
||||
Gcm.ENABLE_GCM -> getSettingsBoolean(key, true)
|
||||
Gcm.FULL_LOG -> getSettingsBoolean(key, true)
|
||||
|
||||
Gcm.LAST_PERSISTENT_ID -> preferences.getString(key, "") ?: ""
|
||||
|
||||
Gcm.NETWORK_MOBILE -> Integer.parseInt(preferences.getString(key, "0") ?: "0")
|
||||
Gcm.NETWORK_WIFI -> Integer.parseInt(preferences.getString(key, "0") ?: "0")
|
||||
Gcm.NETWORK_ROAMING -> Integer.parseInt(preferences.getString(key, "0") ?: "0")
|
||||
Gcm.NETWORK_OTHER -> Integer.parseInt(preferences.getString(key, "0") ?: "0")
|
||||
|
||||
Gcm.LEARNT_MOBILE -> preferences.getInt(key, 300000)
|
||||
Gcm.LEARNT_WIFI -> preferences.getInt(key, 300000)
|
||||
Gcm.LEARNT_OTHER -> preferences.getInt(key, 300000)
|
||||
|
||||
else -> throw IllegalArgumentException("Unknown key: $key")
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateGcm(values: ContentValues) {
|
||||
if (values.size() == 0) return
|
||||
val editor = preferences.edit()
|
||||
values.valueSet().forEach { (key, value) ->
|
||||
// TODO remove log
|
||||
Log.e("TEST", "gcm update: $key = $value")
|
||||
when (key) {
|
||||
Gcm.ENABLE_GCM -> editor.putBoolean(key, value as Boolean)
|
||||
Gcm.FULL_LOG -> editor.putBoolean(key, value as Boolean)
|
||||
|
||||
Gcm.LAST_PERSISTENT_ID -> editor.putString(key, value as String?)
|
||||
|
||||
Gcm.NETWORK_MOBILE -> editor.putString(key, (value as Int).toString())
|
||||
Gcm.NETWORK_WIFI -> editor.putString(key, (value as Int).toString())
|
||||
Gcm.NETWORK_ROAMING -> editor.putString(key, (value as Int).toString())
|
||||
Gcm.NETWORK_OTHER -> editor.putString(key, (value as Int).toString())
|
||||
|
||||
Gcm.LEARNT_MOBILE -> editor.putInt(key, value as Int)
|
||||
Gcm.LEARNT_WIFI -> editor.putInt(key, value as Int)
|
||||
Gcm.LEARNT_OTHER -> editor.putInt(key, value as Int)
|
||||
|
||||
else -> throw IllegalArgumentException("Unknown key: $key")
|
||||
}
|
||||
}
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
private fun queryAuth(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
|
||||
when (key) {
|
||||
Auth.TRUST_GOOGLE -> getSettingsBoolean(key, true)
|
||||
Auth.VISIBLE -> getSettingsBoolean(key, false)
|
||||
else -> throw IllegalArgumentException("Unknown key: $key")
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateAuth(values: ContentValues) {
|
||||
if (values.size() == 0) return
|
||||
val editor = preferences.edit()
|
||||
values.valueSet().forEach { (key, value) ->
|
||||
// TODO remove log
|
||||
Log.e("TEST", "auth update: $key = $value")
|
||||
when (key) {
|
||||
Auth.TRUST_GOOGLE -> editor.putBoolean(key, value as Boolean)
|
||||
Auth.VISIBLE -> editor.putBoolean(key, value as Boolean)
|
||||
else -> throw IllegalArgumentException("Unknown key: $key")
|
||||
}
|
||||
}
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
private fun MatrixCursor.addRow(
|
||||
p: Array<out String>,
|
||||
valueGetter: (String) -> Any
|
||||
): MatrixCursor {
|
||||
val row = newRow()
|
||||
for (key in p) row.add(valueGetter.invoke(key).apply {
|
||||
// TODO remove log
|
||||
Log.e("TEST", "$key = $this")
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getType(uri: Uri): String {
|
||||
return "vnd.android.cursor.item/vnd.$AUTHORITY.${uri.path}"
|
||||
}
|
||||
|
||||
override fun insert(uri: Uri, values: ContentValues?): Uri? {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current setting of the given [key]
|
||||
* using the default value from [systemDefaultPreferences] or [def] if not available.
|
||||
* @return the current setting as [Int], because [ContentProvider] does not support [Boolean].
|
||||
*/
|
||||
private fun getSettingsBoolean(key: String, def: Boolean): Int {
|
||||
val default = systemDefaultPreferences?.getBoolean(key, def) ?: def
|
||||
return if (preferences.getBoolean(key, default)) 1 else 0
|
||||
}
|
||||
}
|
@ -34,11 +34,12 @@ class DeviceRegistrationFragment : Fragment(R.layout.device_registration_fragmen
|
||||
lifecycleScope.launchWhenResumed {
|
||||
val info = getCheckinServiceInfo(requireContext())
|
||||
val newConfiguration = info.configuration.copy(enabled = newStatus)
|
||||
displayServiceInfo(setCheckinServiceConfiguration(requireContext(), newConfiguration))
|
||||
setCheckinServiceConfiguration(requireContext(), newConfiguration)
|
||||
displayServiceInfo(info.copy(configuration = newConfiguration))
|
||||
}
|
||||
}
|
||||
|
||||
fun displayServiceInfo(serviceInfo: ServiceInfo) {
|
||||
private fun displayServiceInfo(serviceInfo: ServiceInfo) {
|
||||
binding.checkinEnabled = serviceInfo.configuration.enabled
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ import org.microg.gms.gcm.ServiceInfo
|
||||
import org.microg.gms.gcm.getGcmServiceInfo
|
||||
import org.microg.gms.gcm.setGcmServiceConfiguration
|
||||
|
||||
@Suppress("Warnings")
|
||||
class PushNotificationFragment : Fragment(R.layout.push_notification_fragment) {
|
||||
lateinit var binding: PushNotificationFragmentBinding
|
||||
|
||||
@ -33,11 +34,12 @@ class PushNotificationFragment : Fragment(R.layout.push_notification_fragment) {
|
||||
lifecycleScope.launchWhenResumed {
|
||||
val info = getGcmServiceInfo(requireContext())
|
||||
val newConfiguration = info.configuration.copy(enabled = newStatus)
|
||||
displayServiceInfo(setGcmServiceConfiguration(requireContext(), newConfiguration))
|
||||
setGcmServiceConfiguration(requireContext(), newConfiguration)
|
||||
displayServiceInfo(info.copy(configuration = newConfiguration))
|
||||
}
|
||||
}
|
||||
|
||||
fun displayServiceInfo(serviceInfo: ServiceInfo) {
|
||||
private fun displayServiceInfo(serviceInfo: ServiceInfo) {
|
||||
binding.gcmEnabled = serviceInfo.configuration.enabled
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,9 @@ package org.microg.gms.ui
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.Preference
|
||||
@ -17,6 +19,9 @@ import com.mgoogle.android.gms.R
|
||||
import org.microg.gms.checkin.CheckinClient
|
||||
import org.microg.gms.checkin.getCheckinServiceInfo
|
||||
import org.microg.gms.gcm.GcmDatabase
|
||||
import org.microg.gms.gcm.McsConstants.ACTION_RECONNECT
|
||||
import org.microg.gms.gcm.McsService
|
||||
import org.microg.gms.gcm.TriggerReceiver
|
||||
import org.microg.gms.gcm.getGcmServiceInfo
|
||||
import org.microg.tools.ui.ResourceSettingsFragment
|
||||
|
||||
@ -73,16 +78,22 @@ class SettingsFragment : ResourceSettingsFragment() {
|
||||
}
|
||||
|
||||
private suspend fun updateDetails() {
|
||||
findPreference<Preference>(PREF_GCM)?.summary = if (getGcmServiceInfo(requireContext()).configuration.enabled) {
|
||||
val context = requireContext()
|
||||
val gcmServiceInfo = getGcmServiceInfo(context)
|
||||
if (gcmServiceInfo.configuration.enabled) {
|
||||
val database = GcmDatabase(context)
|
||||
val regCount = database.registrationList.size
|
||||
// check if we are connected as we should be and re-connect if not
|
||||
if (!gcmServiceInfo.connected) {
|
||||
context.sendBroadcast(Intent(ACTION_RECONNECT, null, context, TriggerReceiver::class.java))
|
||||
}
|
||||
database.close()
|
||||
getString(R.string.service_status_enabled_short) + " - " + resources.getQuantityString(R.plurals.gcm_registered_apps_counter, regCount, regCount)
|
||||
} else {
|
||||
getString(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_CHECKIN)?.setSummary(if (getCheckinServiceInfo(context).configuration.enabled) R.string.service_status_enabled_short else R.string.service_status_disabled_short)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
Loading…
Reference in New Issue
Block a user