Merge remote-tracking branch 'origin/master' into cast-mvp

This commit is contained in:
Adam Mills 2019-03-10 16:47:36 -04:00
commit 3c1ffe1388
No known key found for this signature in database
GPG Key ID: 7733DCD6D0428689
37 changed files with 690 additions and 307 deletions

View File

@ -0,0 +1,88 @@
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 66c497e9977..c1b2e703109 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2341,6 +2341,13 @@
android:description="@string/permdesc_getPackageSize"
android:protectionLevel="normal" />
+ <!-- @hide Allows an application to change the package signature as
+ seen by applications -->
+ <permission android:name="android.permission.FAKE_PACKAGE_SIGNATURE"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_fakePackageSignature"
+ android:description="@string/permdesc_fakePackageSignature" />
+
<!-- @deprecated No longer useful, see
{@link android.content.pm.PackageManager#addPackageToPreferred}
for details. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0b5dd7e70e8..bbdba64f2ba 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1650,6 +1650,8 @@
<string-array name="config_locationProviderPackageNames" translatable="false">
<!-- The standard AOSP fused location provider -->
<item>com.android.location.fused</item>
+ <!-- The (faked) microg fused location provider (a free reimplementation) -->
+ <item>com.google.android.gms</item>
</string-array>
<!-- This string array can be overriden to enable test location providers initially. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3c5159c89bf..7583f1c567f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -786,6 +786,11 @@
<!-- Permissions -->
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_fakePackageSignature">Spoof package signature</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_fakePackageSignature">Allows the app to pretend to be a different app. Malicious applications might be able to use this to access private application data. Legitimate uses include an emulator pretending to be what it emulates. Grant this permission with caution only!</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_statusBar">disable or modify status bar</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_statusBar">Allows the app to disable the status bar or add and remove system icons.</string>
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9ed2b9c1854..4c5ce24cfa7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3937,8 +3937,9 @@ public class PackageManagerService extends IPackageManager.Stub
final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions)
? Collections.<String>emptySet() : permissionsState.getPermissions(userId);
- PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
- ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
+ PackageInfo packageInfo = mayFakeSignature(p, PackageParser.generatePackageInfo(p, gids, flags,
+ ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId),
+ permissions);
if (packageInfo == null) {
return null;
@@ -3974,6 +3975,24 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ private PackageInfo mayFakeSignature(PackageParser.Package p, PackageInfo pi,
+ Set<String> permissions) {
+ try {
+ if (permissions.contains("android.permission.FAKE_PACKAGE_SIGNATURE")
+ && p.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1
+ && p.mAppMetaData != null) {
+ String sig = p.mAppMetaData.getString("fake-signature");
+ if (sig != null) {
+ pi.signatures = new Signature[] {new Signature(sig)};
+ }
+ }
+ } catch (Throwable t) {
+ // We should never die because of any failures, this is system code!
+ Log.w("PackageManagerService.FAKE_PACKAGE_SIGNATURE", t);
+ }
+ return pi;
+ }
+
@Override
public void checkPackageStartable(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();

View File

@ -57,15 +57,16 @@ def execResult(...args) {
return stdout.toString().trim()
}
def gmsVersion = "12.8.79"
def gmsVersion = "13.2.80"
def gmsVersionCode = Integer.parseInt(gmsVersion.replaceAll('\\.', ''))
def gitVersionBase = execResult('git', 'describe', '--tags', '--abbrev=0').substring(1)
def gitCommitCount = Integer.parseInt(execResult('git', 'rev-list', '--count', "v$gitVersionBase..HEAD"))
def gitCommitId = execResult('git', 'show-ref', '--abbrev=7', '--head', 'HEAD').split(' ')[0]
def gitDirty = execResult('git', 'status', '--porcelain').size() > 0
def ourVersionBase = gitVersionBase.substring(0, gitVersionBase.lastIndexOf('.'))
def ourVersionCode = gmsVersionCode * 1000 + gitCommitCount + (gitDirty ? 1 : 0)
def ourVersionName = "$ourVersionBase.$gmsVersionCode" + (gitCommitCount > 0 ? "-$gitCommitCount-$gitCommitId" : "") + (gitDirty ? "-dirty" : "")
def ourVersionMinor = Integer.parseInt(ourVersionBase.substring(ourVersionBase.lastIndexOf('.') + 1))
def ourVersionCode = gmsVersionCode * 1000 + ourVersionMinor * 2 + (gitCommitCount > 0 || gitDirty ? 1 : 0)
def ourVersionName = "$ourVersionBase.$gmsVersionCode" + (gitCommitCount > 0 && !gitDirty ? "-$gitCommitCount" : "") + (gitDirty ? "-dirty" : "") + (gitCommitCount > 0 && !gitDirty ? " ($gitCommitId)" : "")
logger.lifecycle('Starting build for version {} ({})...', ourVersionName, ourVersionCode)
android {

View File

@ -213,16 +213,18 @@
android:permission="com.google.android.c2dm.permission.RECEIVE">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.UNREGISTER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
<receiver android:name="org.microg.gms.gcm.PushRegisterReceiver">
<intent-filter>
<action android:name="com.google.iid.TOKEN_REQUEST"/>
</intent-filter>
</receiver>
<service android:name="org.microg.gms.gcm.McsService"/>
<receiver
@ -419,9 +421,11 @@
<!-- microG custom UI -->
<!-- microG Settings shown in Launcher -->
<activity
android:name="org.microg.gms.ui.SettingsActivity"
android:icon="@mipmap/ic_microg_settings"
android:roundIcon="@mipmap/ic_microg_settings"
android:label="@string/gms_settings_name"
android:theme="@style/Theme.AppCompat.Settings.Dashboard">
<intent-filter>
@ -429,8 +433,27 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.APPLICATION_PREFERENCES"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<!-- microG Settings embedded in System Settings on SDK 23 and newer -->
<activity-alias
android:name="org.microg.gms.ui.SettingsActivityLink"
android:targetActivity="org.microg.gms.ui.SettingsActivity"
android:icon="@drawable/microg_light_color_24"
android:label="@string/gms_settings_name"
android:theme="@style/Theme.AppCompat.Settings.Dashboard">
<intent-filter>
<action android:name="com.android.settings.action.EXTRA_SETTINGS"/>
</intent-filter>
<meta-data android:name="com.android.settings.category" android:value="com.android.settings.category.device"/>
<meta-data android:name="com.android.settings.icon" android:resource="@drawable/microg_light_color_24"/>
<meta-data android:name="com.android.settings.summary" android:resource="@string/gms_settings_summary"/>
</activity-alias>
<activity
android:name="org.microg.gms.ui.AskPushPermission"
android:excludeFromRecents="true"

View File

@ -73,6 +73,7 @@ import static android.view.View.VISIBLE;
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
import static org.microg.gms.common.Constants.MAX_REFERENCE_VERSION;
import android.os.Build;
public class LoginActivity extends AssistantActivity {
public static final String TMPL_NEW_ACCOUNT = "new_account";
@ -131,6 +132,8 @@ public class LoginActivity extends AssistantActivity {
} else {
retrieveRtToken(getIntent().getStringExtra(EXTRA_TOKEN));
}
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
init();
} else {
setMessage(R.string.auth_before_connect);
setBackButtonText(android.R.string.cancel);

View File

@ -81,7 +81,13 @@ public class HttpFormClient {
os.close();
if (connection.getResponseCode() != 200) {
throw new IOException(connection.getResponseMessage());
String error = connection.getResponseMessage();
try {
error = new String(Utils.readStreamToEnd(connection.getErrorStream()));
} catch (IOException e) {
// Ignore
}
throw new IOException(error);
}
String result = new String(Utils.readStreamToEnd(connection.getInputStream()));

View File

@ -52,11 +52,13 @@ public class PackageUtils {
KNOWN_GOOGLE_PACKAGES.put("com.google.android.apps.playconsole", "d6c35e55b481aefddd74152ca7254332739a81d6");
KNOWN_GOOGLE_PACKAGES.put("com.google.android.apps.travel.onthego", "0cbe08032217d45e61c0bc72f294395ee9ecb5d5");
KNOWN_GOOGLE_PACKAGES.put("com.google.android.apps.tycho", "01b844184e360686aa98b48eb16e05c76d4a72ad");
KNOWN_GOOGLE_PACKAGES.put("com.google.android.contacts", "ee3e2b5d95365c5a1ccc2d8dfe48d94eb33b3ebe");
KNOWN_GOOGLE_PACKAGES.put("com.google.android.wearable.app", "a197f9212f2fed64f0ff9c2a4edf24b9c8801c8c");
KNOWN_GOOGLE_PACKAGES.put("com.google.android.apps.youtube.music", "afb0fed5eeaebdd86f56a97742f4b6b33ef59875");
KNOWN_GOOGLE_PACKAGES.put("com.google.android.vr.home", "fc1edc68f7e3e4963c998e95fc38f3de8d1bfc96");
KNOWN_GOOGLE_PACKAGES.put("com.google.vr.cyclops", "188c5ca3863fa121216157a5baa80755ceda70ab");
KNOWN_GOOGLE_PACKAGES.put("com.waze", "35b438fe1bc69d975dc8702dc16ab69ebf65f26f");
KNOWN_GOOGLE_PACKAGES.put("com.google.android.apps.wellbeing", "4ebdd02380f1fa0b6741491f0af35625dba76e9f");
}
public static boolean isGooglePackage(Context context, String packageName) {
@ -154,4 +156,12 @@ public class PackageUtils {
return -1;
}
}
public static String versionName(Context context, String packageName) {
try {
return context.getPackageManager().getPackageInfo(packageName, 0).versionName;
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
}

View File

@ -0,0 +1,151 @@
/*
* Copyright (C) 2018 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.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import org.microg.gms.checkin.LastCheckinInfo;
import org.microg.gms.common.PackageUtils;
import org.microg.gms.common.Utils;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTRATION;
import static org.microg.gms.gcm.GcmConstants.ERROR_SERVICE_NOT_AVAILABLE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_APP;
import static org.microg.gms.gcm.GcmConstants.EXTRA_ERROR;
class PushRegisterHandler extends Handler {
private static final String TAG = "GmsGcmRegisterHdl";
private Context context;
private int callingUid;
private GcmDatabase database;
public PushRegisterHandler(Context context, GcmDatabase database) {
this.context = context;
this.database = database;
}
@Override
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
this.callingUid = Binder.getCallingUid();
return super.sendMessageAtTime(msg, uptimeMillis);
}
private void sendReply(int what, int id, Messenger replyTo, Bundle data) {
if (what == 0) {
Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION);
outIntent.putExtras(data);
Message message = Message.obtain();
message.obj = outIntent;
try {
replyTo.send(message);
} catch (RemoteException e) {
Log.w(TAG, e);
}
} else {
Bundle messageData = new Bundle();
messageData.putBundle("data", data);
Message response = Message.obtain();
response.what = what;
response.arg1 = id;
response.setData(messageData);
try {
replyTo.send(response);
} catch (RemoteException e) {
Log.w(TAG, e);
}
}
}
private void replyError(int what, int id, Messenger replyTo, String errorMessage) {
Bundle bundle = new Bundle();
bundle.putString(EXTRA_ERROR, errorMessage);
sendReply(what, id, replyTo, bundle);
}
private void replyNotAvailable(int what, int id, Messenger replyTo) {
replyError(what, id, replyTo, ERROR_SERVICE_NOT_AVAILABLE);
}
@Override
public void handleMessage(Message msg) {
if (msg.what == 0) {
if (msg.obj instanceof Intent) {
Message nuMsg = Message.obtain();
nuMsg.what = msg.what;
nuMsg.arg1 = 0;
nuMsg.replyTo = null;
PendingIntent pendingIntent = ((Intent) msg.obj).getParcelableExtra(EXTRA_APP);
String packageName = PackageUtils.packageFromPendingIntent(pendingIntent);
Bundle data = new Bundle();
data.putBoolean("oneWay", false);
data.putString("pkg", packageName);
data.putBundle("data", msg.getData());
nuMsg.setData(data);
msg = nuMsg;
} else {
return;
}
}
int what = msg.what;
int id = msg.arg1;
Messenger replyTo = msg.replyTo;
if (replyTo == null) {
Log.w(TAG, "replyTo is null");
return;
}
Bundle data = msg.getData();
if (data.getBoolean("oneWay", false)) {
Log.w(TAG, "oneWay requested");
return;
}
String packageName = data.getString("pkg");
Bundle subdata = data.getBundle("data");
String sender = subdata.getString("sender");
boolean delete = subdata.get("delete") != null;
try {
PackageUtils.checkPackageUid(context, packageName, callingUid);
} catch (SecurityException e) {
Log.w(TAG, e);
return;
}
// TODO: We should checkin and/or ask for permission here.
PushRegisterManager.completeRegisterRequest(context, database,
new RegisterRequest()
.build(Utils.getBuild(context))
.sender(sender)
.checkin(LastCheckinInfo.read(context))
.app(packageName)
.delete(delete)
.appid(subdata.getString("appid"), subdata.getString("gmp_app_id")),
bundle -> sendReply(what, id, replyTo, bundle));
}
}

View File

@ -0,0 +1,168 @@
/*
* Copyright (C) 2018 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.os.Bundle;
import android.util.Log;
import org.microg.gms.checkin.LastCheckinInfo;
import org.microg.gms.common.HttpFormClient;
import org.microg.gms.common.PackageUtils;
import org.microg.gms.common.Utils;
import java.io.IOException;
import static org.microg.gms.gcm.GcmConstants.ERROR_SERVICE_NOT_AVAILABLE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_ERROR;
import static org.microg.gms.gcm.GcmConstants.EXTRA_REGISTRATION_ID;
import static org.microg.gms.gcm.GcmConstants.EXTRA_RETRY_AFTER;
import static org.microg.gms.gcm.GcmConstants.EXTRA_UNREGISTERED;
public class PushRegisterManager {
private static final String TAG = "GmsGcmRegisterMgr";
public static RegisterResponse unregister(Context context, String packageName, String pkgSignature, String sender, String info) {
GcmDatabase database = new GcmDatabase(context);
RegisterResponse response = new RegisterResponse();
try {
response = new RegisterRequest()
.build(Utils.getBuild(context))
.sender(sender)
.info(info)
.checkin(LastCheckinInfo.read(context))
.app(packageName, pkgSignature)
.delete(true)
.getResponse();
} catch (IOException e) {
Log.w(TAG, e);
}
if (!packageName.equals(response.deleted)) {
database.noteAppRegistrationError(packageName, response.responseText);
} else {
database.noteAppUnregistered(packageName, pkgSignature);
}
database.close();
return response;
}
public interface BundleCallback {
void onResult(Bundle bundle);
}
public static void completeRegisterRequest(Context context, GcmDatabase database, RegisterRequest request, BundleCallback callback) {
completeRegisterRequest(context, database, null, request, callback);
}
public static void completeRegisterRequest(Context context, GcmDatabase database, String requestId, RegisterRequest request, BundleCallback callback) {
if (request.app != null) {
if (request.appSignature == null)
request.appSignature = PackageUtils.firstSignatureDigest(context, request.app);
if (request.appVersion <= 0)
request.appVersion = PackageUtils.versionCode(context, request.app);
if (request.appVersionName == null)
request.appVersionName = PackageUtils.versionName(context, request.app);
}
GcmDatabase.App app = database.getApp(request.app);
GcmPrefs prefs = GcmPrefs.get(context);
if (!request.delete) {
if (!prefs.isEnabled() ||
(app != null && !app.allowRegister) ||
LastCheckinInfo.read(context).lastCheckin <= 0 ||
(app == null && prefs.isConfirmNewApps())) {
Bundle bundle = new Bundle();
bundle.putString(EXTRA_ERROR, ERROR_SERVICE_NOT_AVAILABLE);
callback.onResult(bundle);
return;
}
} else {
if (database.getRegistrationsByApp(request.app).isEmpty()) {
Bundle bundle = new Bundle();
bundle.putString(EXTRA_UNREGISTERED, attachRequestId(request.app, requestId));
callback.onResult(bundle);
return;
}
}
request.getResponseAsync(new HttpFormClient.Callback<RegisterResponse>() {
@Override
public void onResponse(RegisterResponse response) {
callback.onResult(handleResponse(database, request, response, requestId));
}
@Override
public void onException(Exception e) {
Log.w(TAG, e);
callback.onResult(handleResponse(database, request, e, requestId));
}
});
}
private static Bundle handleResponse(GcmDatabase database, RegisterRequest request, RegisterResponse response, String requestId) {
return handleResponse(database, request, response, null, requestId);
}
private static Bundle handleResponse(GcmDatabase database, RegisterRequest request, Exception e, String requestId) {
return handleResponse(database, request, null, e, requestId);
}
private static Bundle handleResponse(GcmDatabase database, RegisterRequest request, RegisterResponse response, Exception e, String requestId) {
Bundle resultBundle = new Bundle();
if (response == null && e == null) {
resultBundle.putString(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));
} else if (e != null) {
if (e.getMessage() != null && e.getMessage().startsWith("Error=")) {
String errorMessage = e.getMessage().substring(6);
database.noteAppRegistrationError(request.app, errorMessage);
resultBundle.putString(EXTRA_ERROR, attachRequestId(errorMessage, requestId));
} else {
resultBundle.putString(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));
}
} else {
if (!request.delete) {
if (response.token == null) {
database.noteAppRegistrationError(request.app, response.responseText);
resultBundle.putString(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));
} else {
database.noteAppRegistered(request.app, request.appSignature, response.token);
resultBundle.putString(EXTRA_REGISTRATION_ID, attachRequestId(response.token, requestId));
}
} else {
if (!request.app.equals(response.deleted) && !request.app.equals(response.token)) {
database.noteAppRegistrationError(request.app, response.responseText);
resultBundle.putString(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));
} else {
database.noteAppUnregistered(request.app, request.appSignature);
resultBundle.putString(EXTRA_UNREGISTERED, attachRequestId(request.app, requestId));
}
}
if (response.retryAfter != null && !response.retryAfter.contains(":")) {
resultBundle.putLong(EXTRA_RETRY_AFTER, Long.parseLong(response.retryAfter));
}
}
return resultBundle;
}
public static String attachRequestId(String msg, String requestId) {
if (requestId == null) return msg;
return "|ID|" + requestId + "|" + msg;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2018 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.support.v4.content.WakefulBroadcastReceiver;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTER;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_UNREGISTER;
public class PushRegisterReceiver extends WakefulBroadcastReceiver {
private static final String TAG = "GmsGcmRegisterRcv";
@Override
public void onReceive(Context context, Intent intent) {
Intent intent2 = new Intent(context, PushRegisterService.class);
if (intent.getExtras().get("delete") != null) {
intent2.setAction(ACTION_C2DM_UNREGISTER);
} else {
intent2.setAction(ACTION_C2DM_REGISTER);
}
intent2.putExtras(intent.getExtras());
startWakefulService(context, intent2);
}
}

View File

@ -22,15 +22,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.support.v4.content.WakefulBroadcastReceiver;
import android.util.Log;
import org.microg.gms.checkin.CheckinService;
@ -39,8 +35,6 @@ import org.microg.gms.common.PackageUtils;
import org.microg.gms.common.Utils;
import org.microg.gms.ui.AskPushPermission;
import java.io.IOException;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTER;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTRATION;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_UNREGISTER;
@ -51,10 +45,7 @@ import static org.microg.gms.gcm.GcmConstants.EXTRA_ERROR;
import static org.microg.gms.gcm.GcmConstants.EXTRA_KID;
import static org.microg.gms.gcm.GcmConstants.EXTRA_MESSENGER;
import static org.microg.gms.gcm.GcmConstants.EXTRA_PENDING_INTENT;
import static org.microg.gms.gcm.GcmConstants.EXTRA_REGISTRATION_ID;
import static org.microg.gms.gcm.GcmConstants.EXTRA_RETRY_AFTER;
import static org.microg.gms.gcm.GcmConstants.EXTRA_SENDER;
import static org.microg.gms.gcm.GcmConstants.EXTRA_UNREGISTERED;
public class PushRegisterService extends IntentService {
private static final String TAG = "GmsGcmRegisterSvc";
@ -80,33 +71,9 @@ public class PushRegisterService extends IntentService {
database.close();
}
public static RegisterResponse register(Context context, String packageName, String pkgSignature, String sender, String info) {
GcmDatabase database = new GcmDatabase(context);
RegisterResponse response = register(context, packageName, pkgSignature, sender, info, false);
String regId = response.token;
if (regId != null) {
database.noteAppRegistered(packageName, pkgSignature, regId);
} else {
database.noteAppRegistrationError(packageName, response.responseText);
}
database.close();
return response;
}
public static RegisterResponse unregister(Context context, String packageName, String pkgSignature, String sender, String info) {
GcmDatabase database = new GcmDatabase(context);
RegisterResponse response = register(context, packageName, pkgSignature, sender, info, true);
if (!packageName.equals(response.deleted)) {
database.noteAppRegistrationError(packageName, response.responseText);
} else {
database.noteAppUnregistered(packageName, pkgSignature);
}
database.close();
return response;
}
@Override
protected void onHandleIntent(Intent intent) {
WakefulBroadcastReceiver.completeWakefulIntent(intent);
Log.d(TAG, "onHandleIntent: " + intent);
String requestId = null;
@ -117,42 +84,35 @@ public class PushRegisterService extends IntentService {
}
}
if (GcmPrefs.get(this).isEnabled()) {
if (LastCheckinInfo.read(this).lastCheckin > 0) {
try {
if (ACTION_C2DM_UNREGISTER.equals(intent.getAction()) ||
(ACTION_C2DM_REGISTER.equals(intent.getAction()) && "1".equals(intent.getStringExtra(EXTRA_DELETE)))) {
unregister(intent, requestId);
} else if (ACTION_C2DM_REGISTER.equals(intent.getAction())) {
register(intent, requestId);
}
} catch (Exception e) {
Log.w(TAG, e);
if (LastCheckinInfo.read(this).lastCheckin > 0) {
try {
if (ACTION_C2DM_UNREGISTER.equals(intent.getAction()) ||
(ACTION_C2DM_REGISTER.equals(intent.getAction()) && "1".equals(intent.getStringExtra(EXTRA_DELETE)))) {
unregister(intent, requestId);
} else if (ACTION_C2DM_REGISTER.equals(intent.getAction())) {
register(intent, requestId);
}
} else if (!intent.getBooleanExtra(EXTRA_SKIP_TRY_CHECKIN, false)) {
Log.d(TAG, "No checkin yet, trying to checkin");
intent.putExtra(EXTRA_SKIP_TRY_CHECKIN, true);
Intent subIntent = new Intent(this, CheckinService.class);
subIntent.putExtra(CheckinService.EXTRA_FORCE_CHECKIN, true);
subIntent.putExtra(CheckinService.EXTRA_CALLBACK_INTENT, intent);
startService(subIntent);
} catch (Exception e) {
Log.w(TAG, e);
}
} else {
// GCM is disabled, deny registration
replyNotAvailable(this, intent, null, requestId);
} else if (!intent.getBooleanExtra(EXTRA_SKIP_TRY_CHECKIN, false)) {
Log.d(TAG, "No checkin yet, trying to checkin");
intent.putExtra(EXTRA_SKIP_TRY_CHECKIN, true);
Intent subIntent = new Intent(this, CheckinService.class);
subIntent.putExtra(CheckinService.EXTRA_FORCE_CHECKIN, true);
subIntent.putExtra(CheckinService.EXTRA_CALLBACK_INTENT, intent);
startService(subIntent);
}
}
private void register(final Intent intent, String requestId) {
PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_APP);
final String packageName = PackageUtils.packageFromPendingIntent(pendingIntent);
Log.d(TAG, "register[req]: " + intent.toString() + " extras=" + intent.getExtras());
GcmDatabase.App app = database.getApp(packageName);
if (app == null && GcmPrefs.get(this).isConfirmNewApps()) {
try {
PackageManager pm = getPackageManager();
ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
getPackageManager().getApplicationInfo(packageName, 0); // Check package exists
Intent i = new Intent(this, AskPushPermission.class);
i.putExtra(EXTRA_PENDING_INTENT, intent);
i.putExtra(EXTRA_APP, packageName);
@ -161,46 +121,31 @@ public class PushRegisterService extends IntentService {
} catch (PackageManager.NameNotFoundException e) {
replyNotAvailable(this, intent, packageName, requestId);
}
} else if (app != null && !app.allowRegister) {
replyNotAvailable(this, intent, packageName, requestId);
} else {
registerAndReply(this, intent, packageName, requestId);
registerAndReply(this, database, intent, packageName, requestId);
}
}
public static void replyNotAvailable(Context context, Intent intent, String packageName, String requestId) {
if (packageName == null) {
PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_APP);
packageName = PackageUtils.packageFromPendingIntent(pendingIntent);
}
if (packageName == null) {
// skip reply
return;
}
Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION);
outIntent.putExtra(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));
Log.d(TAG, "registration not allowed");
outIntent.putExtra(EXTRA_ERROR, PushRegisterManager.attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));
sendReply(context, intent, packageName, outIntent);
}
public static void registerAndReply(Context context, Intent intent, String packageName, String requestId) {
String sender = intent.getStringExtra(EXTRA_SENDER);
String appSignature = PackageUtils.firstSignatureDigest(context, packageName);
String regId = register(context, packageName, appSignature, sender, null).token;
Intent outIntent = createRegistrationReply(regId, requestId);
Log.d(TAG, "register[res]: " + outIntent + " extras=" + outIntent.getExtras());
sendReply(context, intent, packageName, outIntent);
}
private static Intent createRegistrationReply(String regId, String requestId) {
Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION);
if (regId != null) {
outIntent.putExtra(EXTRA_REGISTRATION_ID, attachRequestId(regId, requestId));
} else {
outIntent.putExtra(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));
}
return outIntent;
public static void registerAndReply(Context context, GcmDatabase database, Intent intent, String packageName, String requestId) {
Log.d(TAG, "register[req]: " + intent.toString() + " extras=" + intent.getExtras());
PushRegisterManager.completeRegisterRequest(context, database,
new RegisterRequest()
.build(Utils.getBuild(context))
.sender(intent.getStringExtra(EXTRA_SENDER))
.checkin(LastCheckinInfo.read(context))
.app(packageName),
bundle -> {
Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION);
outIntent.putExtras(bundle);
Log.d(TAG, "register[res]: " + outIntent.toString() + " extras=" + outIntent.getExtras());
sendReply(context, intent, packageName, outIntent);
});
}
private static void sendReply(Context context, Intent intent, String packageName, Intent outIntent) {
@ -220,55 +165,23 @@ public class PushRegisterService extends IntentService {
context.sendOrderedBroadcast(outIntent, null);
}
public static RegisterResponse register(Context context, String app, String appSignature, String sender, String info, boolean delete) {
try {
RegisterResponse response = new RegisterRequest()
.build(Utils.getBuild(context))
.sender(sender)
.info(info)
.checkin(LastCheckinInfo.read(context))
.app(app, appSignature, PackageUtils.versionCode(context, app))
.delete(delete)
.getResponse();
Log.d(TAG, "received response: " + response);
return response;
} catch (IOException e) {
Log.w(TAG, e);
}
return new RegisterResponse();
}
private void unregister(Intent intent, String requestId) {
PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_APP);
String packageName = PackageUtils.packageFromPendingIntent(pendingIntent);
Log.d(TAG, "unregister[req]: " + intent.toString() + " extras=" + intent.getExtras());
Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION);
String appSignature = PackageUtils.firstSignatureDigest(this, packageName);
if (database.getRegistration(packageName, appSignature) == null) {
outIntent.putExtra(EXTRA_UNREGISTERED, attachRequestId(packageName, requestId));
} else {
RegisterResponse response = unregister(this, packageName, appSignature, null, null);
if (!packageName.equals(response.deleted)) {
outIntent.putExtra(EXTRA_ERROR, attachRequestId(ERROR_SERVICE_NOT_AVAILABLE, requestId));
if (response.retryAfter != null && !response.retryAfter.contains(":")) {
outIntent.putExtra(EXTRA_RETRY_AFTER, Long.parseLong(response.retryAfter));
}
} else {
outIntent.putExtra(EXTRA_UNREGISTERED, attachRequestId(packageName, requestId));
}
}
Log.d(TAG, "unregister[res]: " + outIntent.toString() + " extras=" + outIntent.getExtras());
sendReply(this, intent, packageName, outIntent);
}
private static String attachRequestId(String msg, String requestId) {
if (requestId == null) return msg;
return "|ID|" + requestId + "|" + msg;
PushRegisterManager.completeRegisterRequest(this, database,
new RegisterRequest()
.build(Utils.getBuild(this))
.sender(intent.getStringExtra(EXTRA_SENDER))
.checkin(LastCheckinInfo.read(this))
.app(packageName),
bundle -> {
Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION);
outIntent.putExtras(bundle);
Log.d(TAG, "unregister[res]: " + outIntent.toString() + " extras=" + outIntent.getExtras());
sendReply(this, intent, packageName, outIntent);
});
}
@Nullable
@ -276,127 +189,10 @@ public class PushRegisterService extends IntentService {
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind: " + intent.toString());
if (ACTION_C2DM_REGISTER.equals(intent.getAction())) {
Messenger messenger = new Messenger(new FcmHandler(this));
Messenger messenger = new Messenger(new PushRegisterHandler(this, database));
return messenger.getBinder();
}
return super.onBind(intent);
}
private static class FcmRegisterTask extends AsyncTask<Void, Void, RegisterResponse> {
private Context context;
private String packageName;
private String sender;
private Callback callback;
public FcmRegisterTask(Context context, String packageName, String sender, Callback callback) {
this.context = context;
this.packageName = packageName;
this.sender = sender;
this.callback = callback;
}
public interface Callback {
void onResult(RegisterResponse registerResponse);
}
@Override
protected RegisterResponse doInBackground(Void... voids) {
return register(context, packageName, PackageUtils.firstSignatureDigest(context, packageName), sender, null, false);
}
@Override
protected void onPostExecute(RegisterResponse registerResponse) {
callback.onResult(registerResponse);
}
}
private static class FcmHandler extends Handler {
private Context context;
private int callingUid;
public FcmHandler(Context context) {
this.context = context;
}
@Override
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
this.callingUid = Binder.getCallingUid();
return super.sendMessageAtTime(msg, uptimeMillis);
}
@Override
public void handleMessage(Message msg) {
if (msg.what == 0) {
if (msg.obj instanceof Intent) {
Message nuMsg = Message.obtain();
nuMsg.what = msg.what;
nuMsg.arg1 = 0;
nuMsg.replyTo = null;
PendingIntent pendingIntent = ((Intent) msg.obj).getParcelableExtra(EXTRA_APP);
String packageName = PackageUtils.packageFromPendingIntent(pendingIntent);
Bundle data = new Bundle();
data.putBoolean("oneWay", false);
data.putString("pkg", packageName);
data.putBundle("data", msg.getData());
nuMsg.setData(data);
msg = nuMsg;
} else {
return;
}
}
int what = msg.what;
int id = msg.arg1;
Messenger replyTo = msg.replyTo;
if (replyTo == null) {
Log.w(TAG, "replyTo is null");
return;
}
Bundle data = msg.getData();
if (data.getBoolean("oneWay", false)) {
Log.w(TAG, "oneWay requested");
return;
}
String packageName = data.getString("pkg");
Bundle subdata = data.getBundle("data");
String sender = subdata.getString("sender");
try {
PackageUtils.checkPackageUid(context, packageName, callingUid);
} catch (SecurityException e) {
Log.w(TAG, e);
return;
}
new FcmRegisterTask(context, packageName, sender, registerResponse -> {
Bundle data1 = new Bundle();
if (registerResponse != null) {
data1.putString(EXTRA_REGISTRATION_ID, registerResponse.token);
} else {
data1.putString(EXTRA_ERROR, ERROR_SERVICE_NOT_AVAILABLE);
}
if (what == 0) {
Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION);
outIntent.putExtras(data1);
Message message = Message.obtain();
message.obj = outIntent;
try {
replyTo.send(message);
} catch (RemoteException e) {
Log.w(TAG, e);
}
} else {
Bundle messageData = new Bundle();
messageData.putBundle("data", data1);
Message response = Message.obtain();
response.what = what;
response.arg1 = id;
response.setData(messageData);
try {
replyTo.send(response);
} catch (RemoteException e) {
Log.w(TAG, e);
}
}
}).execute();
}
}
}

View File

@ -18,6 +18,7 @@ package org.microg.gms.gcm;
import org.microg.gms.checkin.LastCheckinInfo;
import org.microg.gms.common.Build;
import org.microg.gms.common.Constants;
import org.microg.gms.common.HttpFormClient;
import java.io.IOException;
@ -41,9 +42,11 @@ public class RegisterRequest extends HttpFormClient.Request {
public String appSignature;
@RequestContent("app_ver")
public int appVersion;
@RequestContent("app_ver_name")
public String appVersionName;
@RequestContent("info")
public String info;
@RequestContent("sender")
@RequestContent({"sender", "subtype"})
public String sender;
@RequestContent({"X-GOOG.USER_AID", "device"})
public long androidId;
@ -52,11 +55,22 @@ public class RegisterRequest extends HttpFormClient.Request {
public long securityToken;
public String deviceName;
public String buildVersion;
@RequestContent("osv")
public int sdkVersion;
@RequestContent("gmsv")
public int gmsVersion;
@RequestContent("scope")
public String scope = "*";
@RequestContent("appid")
public String appId;
@RequestContent("gmp_app_id")
public String gmpAppId;
@Override
public void prepare() {
userAgent = String.format(USER_AGENT, deviceName, buildVersion);
auth = "AidLogin " + androidId + ":" + securityToken;
gmsVersion = Constants.MAX_REFERENCE_VERSION;
}
public RegisterRequest checkin(LastCheckinInfo lastCheckinInfo) {
@ -65,10 +79,28 @@ public class RegisterRequest extends HttpFormClient.Request {
return this;
}
public RegisterRequest app(String app, String appSignature, int appVersion) {
public RegisterRequest app(String app) {
this.app = app;
return this;
}
public RegisterRequest app(String app, String appSignature) {
this.app = app;
this.appSignature = appSignature;
return this;
}
public RegisterRequest app(String app, String appSignature, int appVersion, String appVersionName) {
this.app = app;
this.appSignature = appSignature;
this.appVersion = appVersion;
this.appVersionName = appVersionName;
return this;
}
public RegisterRequest appid(String appid, String gmpAppId) {
this.appId = appid;
this.gmpAppId = gmpAppId;
return this;
}
@ -85,6 +117,7 @@ public class RegisterRequest extends HttpFormClient.Request {
public RegisterRequest build(Build build) {
deviceName = build.device;
buildVersion = build.id;
sdkVersion = build.sdk;
return this;
}

View File

@ -28,7 +28,7 @@ public class UnregisterReceiver extends BroadcastReceiver {
List<GcmDatabase.Registration> registrations = database.getRegistrationsByApp(packageName);
boolean deletedAll = true;
for (GcmDatabase.Registration registration : registrations) {
deletedAll &= PushRegisterService.unregister(context, registration.packageName, registration.signature, null, null).deleted != null;
deletedAll &= PushRegisterManager.unregister(context, registration.packageName, registration.signature, null, null).deleted != null;
}
if (deletedAll) {
database.removeApp(packageName);

View File

@ -22,6 +22,7 @@ import android.os.RemoteException;
import android.util.Log;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.dynamic.ObjectWrapper;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.internal.IMarkerDelegate;
@ -42,6 +43,7 @@ public class MarkerImpl extends IMarkerDelegate.Stub implements MarkerItemMarkup
private BitmapDescriptorImpl icon;
private AndroidBitmap oldBitmap;
private boolean removed = false;
private IObjectWrapper tag = null;
public MarkerImpl(String id, MarkerOptions options, MarkupListener listener) {
this.id = id;
@ -264,4 +266,24 @@ public class MarkerImpl extends IMarkerDelegate.Stub implements MarkerItemMarkup
private void prepareMarkerIcon(MarkerItem item) {
item.setMarker(new MarkerSymbol(oldBitmap, options.getAnchorU(), options.getAnchorV(), !options.isFlat()));
}
@Override
public void setZIndex(float zIndex) {
options.zIndex(zIndex);
}
@Override
public float getZIndex() {
return options.getZIndex();
}
@Override
public void setTag(IObjectWrapper obj) {
this.tag = obj;
}
@Override
public IObjectWrapper getTag() {
return this.tag == null ? ObjectWrapper.wrap(null) : this.tag;
}
}

View File

@ -56,13 +56,12 @@ public class PeopleManager {
cursor.close();
databaseHelper.close();
if (url == null) return null;
String urlLastPart = url.substring(3);
String urlLastPart = url.replaceFirst(REGEX_SEARCH_USER_PHOTO, "");
File file = new File(context.getCacheDir(), urlLastPart);
if (!file.getParentFile().mkdirs() && file.exists()) {
return file;
}
if (!network) return null;
url = "https://lh" + url.toCharArray()[1] + ".googleusercontent.com/" + urlLastPart;
try {
URLConnection conn = new URL(url).openConnection();
conn.setDoInput(true);
@ -94,8 +93,7 @@ public class PeopleManager {
ContentValues contentValues = new ContentValues();
contentValues.put("account_name", account.name);
if (info.has("id")) contentValues.put("gaia_id", info.getString("id"));
if (info.has("picture"))
contentValues.put("avatar", info.getString("picture").replaceFirst(REGEX_SEARCH_USER_PHOTO, "~$1/"));
if (info.has("picture")) contentValues.put("avatar", info.getString("picture"));
if (info.has("name")) contentValues.put("display_name", info.getString("name"));
if (info.has("given_name")) contentValues.put("given_name", info.getString("given_name"));
if (info.has("family_name")) contentValues.put("family_name", info.getString("family_name"));

View File

@ -139,15 +139,16 @@ public class Attestation {
}
}
public String attest() throws IOException {
public String attest(String apiKey) throws IOException {
if (payload == null) {
throw new IllegalStateException("missing payload");
}
return attest(new AttestRequest(ByteString.of(payload), droidGaurdResult)).result;
return attest(new AttestRequest(ByteString.of(payload), droidGaurdResult), apiKey).result;
}
private AttestResponse attest(AttestRequest request) throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(SafetyNetPrefs.get(context).getServiceUrl()).openConnection();
private AttestResponse attest(AttestRequest request, String apiKey) throws IOException {
String requestUrl = SafetyNetPrefs.get(context).getServiceUrl() + "?alt=PROTO&key=" + apiKey;
HttpURLConnection connection = (HttpURLConnection) new URL(requestUrl).openConnection();
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);

View File

@ -39,6 +39,7 @@ import java.util.ArrayList;
public class SafetyNetClientServiceImpl extends ISafetyNetService.Stub {
private static final String TAG = "GmsSafetyNetClientImpl";
private static final String DEFAULT_API_KEY = "AIzaSyDqVnJBjE5ymo--oBJt3On7HQx9xNm1RHA";
private Context context;
private String packageName;
@ -52,7 +53,7 @@ public class SafetyNetClientServiceImpl extends ISafetyNetService.Stub {
@Override
public void attest(ISafetyNetCallbacks callbacks, byte[] nonce) throws RemoteException {
attestWithApiKey(callbacks, nonce, null);
attestWithApiKey(callbacks, nonce, DEFAULT_API_KEY);
}
@Override
@ -82,7 +83,7 @@ public class SafetyNetClientServiceImpl extends ISafetyNetService.Stub {
if (dg != null && dg.getStatusCode() == 0 && dg.getResult() != null) {
attestation.setDroidGaurdResult(Base64.encodeToString(dg.getResult(), Base64.NO_WRAP + Base64.NO_PADDING + Base64.URL_SAFE));
}
AttestationData data = new AttestationData(attestation.attest());
AttestationData data = new AttestationData(attestation.attest(apiKey));
callbacks.onAttestationData(Status.SUCCESS, data);
} else {
callbacks.onAttestationData(dg == null ? Status.INTERNAL_ERROR : new Status(dg.getStatusCode()), null);

View File

@ -21,7 +21,7 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
public class SafetyNetPrefs implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String OFFICIAL_ATTEST_URL = "https://www.googleapis.com/androidcheck/v1/attestations/attest?alt=PROTO&key=AIzaSyDqVnJBjE5ymo--oBJt3On7HQx9xNm1RHA";
private static final String OFFICIAL_ATTEST_BASE_URL = "https://www.googleapis.com/androidcheck/v1/attestations/attest";
public static final String PREF_SNET_DISABLED = "snet_disabled";
public static final String PREF_SNET_OFFICIAL = "snet_official";
@ -57,7 +57,7 @@ public class SafetyNetPrefs implements SharedPreferences.OnSharedPreferenceChang
public void update() {
disabled = defaultPreferences.getBoolean(PREF_SNET_DISABLED, true);
official = defaultPreferences.getBoolean(PREF_SNET_OFFICIAL, 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);
@ -88,8 +88,12 @@ public class SafetyNetPrefs implements SharedPreferences.OnSharedPreferenceChang
return official;
}
public boolean isThirdParty() {
return thirdParty;
}
public String getServiceUrl() {
if (official) return OFFICIAL_ATTEST_URL;
if (official) return OFFICIAL_ATTEST_BASE_URL;
return customUrl;
}
}

View File

@ -66,7 +66,7 @@ public class AskPushPermission extends FragmentActivity {
new Thread(new Runnable() {
@Override
public void run() {
PushRegisterService.registerAndReply(AskPushPermission.this, intent, packageName, requestId);
PushRegisterService.registerAndReply(AskPushPermission.this, database, intent, packageName, requestId);
}
}).start();
finish();

View File

@ -7,7 +7,6 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.StringRes;
import android.support.v14.preference.SwitchPreference;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
@ -21,7 +20,7 @@ import android.widget.TextView;
import com.google.android.gms.R;
import org.microg.gms.gcm.GcmDatabase;
import org.microg.gms.gcm.PushRegisterService;
import org.microg.gms.gcm.PushRegisterManager;
import org.microg.tools.ui.AbstractSettingsActivity;
import org.microg.tools.ui.ResourceSettingsFragment;
@ -185,7 +184,7 @@ public class GcmAppFragment extends ResourceSettingsFragment {
@Override
public void run() {
for (GcmDatabase.Registration registration : registrations) {
PushRegisterService.unregister(getContext(), registration.packageName, registration.signature, null, null);
PushRegisterManager.unregister(getContext(), registration.packageName, registration.signature, null, null);
}
getActivity().runOnUiThread(new Runnable() {
@Override

View File

@ -80,7 +80,22 @@ public class SettingsActivity extends AbstractDashboardActivity {
} else {
findPreference(PREF_GCM).setSummary(R.string.abc_capital_off);
}
findPreference(PREF_SNET).setSummary(SafetyNetPrefs.get(getContext()).isEnabled() ? R.string.service_status_enabled : R.string.service_status_disabled);
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) + " / " + snet_info);
} else {
findPreference(PREF_SNET).setSummary(R.string.service_status_disabled);
}
Preferences unifiedNlPrefs = new Preferences(getContext());
int backendCount = TextUtils.isEmpty(unifiedNlPrefs.getLocationBackends()) ? 0 :

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="256"
android:viewportHeight="256"
android:width="256dp"
android:height="256dp">
<path
android:fillColor="#ffffffff" android:pathData="M207.03481 139.53168c0.42667 -3.41333 0.74667 -6.82666 0.74667 -10.45333 0 -3.62667 -0.32 -7.04 -0.74667 -10.45333l22.50667 -17.6c2.02667 -1.599996 2.56 -4.479996 1.28 -6.826666L209.48815 57.291687c-1.28 -2.346666 -4.16 -3.2 -6.50667 -2.346666l-26.56 10.666666c-5.54667 -4.266666 -11.52 -7.786666 -18.02667 -10.453333l-4.05333 -28.266667c-0.32 -2.56 -2.56 -4.48 -5.22667 -4.48h-42.66666c-2.66667 0 -4.90667 1.92 -5.22667 4.48l-4.053331 28.266667c-6.50667 2.666667 -12.48 6.293333 -18.02667 10.453333l-26.56 -10.666666c-2.45333 -0.96 -5.22667 0 -6.50667 2.346666l-21.33333 36.906667c-1.38667 2.34667 -0.74667 5.22667 1.28 6.826666l22.50667 17.6c-0.42667 3.41333 -0.74667 6.93333 -0.74667 10.45333 0 3.52 0.32 7.04 0.74667 10.45333l-22.50667 17.6c-2.02667 1.6 -2.56 4.48 -1.28 6.82667l21.33333 36.90667c1.28 2.34666 4.16 3.2 6.50667 2.34666l26.56 -10.66666c5.54667 4.26666 11.52 7.78666 18.02667 10.45333l4.053331 28.26667c0.32 2.56 2.56 4.48 5.22667 4.48h42.66666c2.66667 0 4.90667 -1.92 5.22667 -4.48l4.05333 -28.26667c6.50667 -2.66667 12.48 -6.29333 18.02667 -10.45333l26.56 10.66666c2.45333 0.96 5.22667 0 6.50667 -2.34666l21.33333 -36.90667c1.28 -2.34667 0.74667 -5.22667 -1.28 -6.82667z">
</path>
</vector>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon
xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_microg_background" />
<foreground android:drawable="@mipmap/ic_microg_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -17,6 +17,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="gms_app_name">microG Services Core</string>
<string name="gms_settings_name">microG Einstellungen</string>
<string name="gms_settings_summary">microG services Core einrichten.</string>
<string name="just_a_sec">Einen kurzen Moment…</string>
<string name="google_account_label">Google</string>
@ -152,11 +153,14 @@ Dies kann einige Minuten dauern."</string>
<string name="pref_snet_status_official_title">Offizielle Server nutzen</string>
<string name="pref_snet_status_official_summary">Erfordert eine ungerootetes ROM und den microG DroidGuard Helper</string>
<string name="pref_snet_status_official_info">offizieller Server</string>
<string name="pref_snet_status_third_party_title">Alternativen Server nutzen</string>
<string name="pref_snet_status_third_party_summary">Alternative Server können auch SafetyNet-Anfragen beantworten, die nicht durch DroidGuard signiert wurden</string>
<string name="pref_snet_status_third_party_info">Dritt-Server</string>
<string name="pref_snet_custom_url_title">Alternative Server URL</string>
<string name="pref_snet_custom_url_summary">Vollständige URL des alternativen Servers der SafetyNet-Anfragen beantwortet</string>
<string name="pref_snet_self_signed_title">Selbst signieren</string>
<string name="pref_snet_self_signed_summary">Statt einen Server zu nutzen, die SafetyNet signature lokal mit einem eigens erstellten Zertifikat signieren. Die meisten Apps werden diese Signaturen nicht akzeptieren.</string>
<string name="pref_snet_status_self_signed_info">selbst-signiertes Zertifikat</string>
</resources>

View File

@ -91,7 +91,7 @@ Ceci peut prendre plusieurs minutes."</string>
<string name="self_check_pkg_vending">Play Store (Phonesky)</string>
<string name="self_check_pkg_gsf">Services Framework (GSF)</string>
<string name="self_check_name_app_installed"><xliff:g example="F-Droid">%1$s</xliff:g> installé : </string>
<string name="self_check_resolution_app_installed">Installez lapplications <xliff:g example="F-Droid">%1$s</xliff:g> ou tout autre compatible. Merci de consulter la documentation pour obtenir la liste des applications compatibles.</string>
<string name="self_check_resolution_app_installed">Installez lapplication <xliff:g example="F-Droid">%1$s</xliff:g> ou tout autre compatible. Merci de consulter la documentation pour obtenir la liste des applications compatibles.</string>
<string name="self_check_name_correct_sig"><xliff:g example="F-Droid">%1$s</xliff:g> dispose de la bonne signature : </string>
<string name="self_check_resolution_correct_sig">Soit lapplication <xliff:g example="F-Droid">%1$s</xliff:g> installée nest pas compatible, soit lusurpation de signature nest pas activée pour celle-ci. Merci de consulter la documentation sur les applications et ROMs compatibles.</string>
@ -125,7 +125,7 @@ Ceci peut prendre plusieurs minutes."</string>
<string name="pref_more_settings">Plus</string>
<string name="pref_gcm_enable_mcs_summary">Google Cloud Messaging est un fournisseur de notifications push utilisés par beaucoup dapplications tierces. Pour lutiliser vous devez activez lenregistrement du terminal.</string>
<string name="pref_gcm_enable_mcs_summary">Google Cloud Messaging est un fournisseur de notifications push utilisé par beaucoup dapplications tierces. Pour lutiliser vous devez activer lenregistrement du terminal.</string>
<string name="pref_gcm_heartbeat_title">Intervalle des signaux de présence Cloud Messaging</string>
<string name="pref_gcm_heartbeat_summary">Lintervalle en secondes auquel le système signale sa présence aux serveurs de Google. Augmenter ce nombre réduira la consommation de batterie mais peu induire un délai dans la réception des messages push.\nDéprécié, sera remplacé dans une prochaine version.</string>
<string name="pref_gcm_apps_title">Applications utilisant Google Cloud Messaging</string>
@ -152,7 +152,7 @@ Ceci peut prendre plusieurs minutes."</string>
<string name="gcm_state_disconnected">Status actuel : Déconnecté</string>
<string name="gcm_state_connected">Status actuel : Connecté depuis <xliff:g example="2 hours ago">%1$s</xliff:g></string>
<string name="snet_intro">Google SafetyNet est un système de certification du terminal, assurant que celui-ci est correctement sécurisé et compatible avec Android CTS. Certaines applications utilisent SafetyNet pour des raisons de sécurité ou comme prérequis anti-altérations.\n\nmicroG GmsCore contient une implémentation libre de SafetyNet, mais les serveurs officiels requièrent que les requêtes SafetyNet soient signées par le système propriétaire DroidGuard. Une version mise en «bac-à-sable» de DroidGuard est disponible dans une application séparée «DroidGuard Helper».
<string name="snet_intro">Google SafetyNet est un système de certification du terminal, assurant que celui-ci est correctement sécurisé et compatible avec Android CTS. Certaines applications utilisent SafetyNet pour des raisons de sécurité ou comme prérequis anti-altérations.\n\nmicroG GmsCore contient une implantation libre de SafetyNet, mais les serveurs officiels requièrent que les requêtes SafetyNet soient signées par le système propriétaire DroidGuard. Une version mise en «bac-à-sable» de DroidGuard est disponible dans une application séparée «DroidGuard Helper».
</string>
<string name="pref_snet_testdrive_title">Tester la certification SafetyNet</string>

View File

@ -108,17 +108,17 @@
<string name="permission_scope_www.googleapis.com_auth_apps.order.readonly">"Помимо общего чтения/записи по протоколу OAuth, следует использовать только для чтения протокол OAuth при извлечении данных клиента."</string>
<string name="permission_scope_www.googleapis.com_auth_apps_reporting_audit.readonly">Доступ к API аудиту администратора только для чтения</string>
<string name="permission_scope_www.googleapis.com_auth_appstate">Область использования App State сервиса.</string>
<string name="permission_scope_www.googleapis.com_auth_bigquery.readonly">Посмотр своих данных в Google BigQuery</string>
<string name="permission_scope_www.googleapis.com_auth_bigquery.readonly">Просмотр своих данных в Google BigQuery</string>
<string name="permission_scope_www.googleapis.com_auth_bigquery">Просмотр и управление своими данными в Google BigQuery</string>
<string name="permission_scope_www.googleapis.com_auth_blogger">Управление своей учетной записи блоггера</string>
<string name="permission_scope_www.googleapis.com_auth_blogger.readonly">Посмотр своей учетной записи блоггера</string>
<string name="permission_scope_www.googleapis.com_auth_blogger.readonly">Просмотр своей учетной записи блоггера</string>
<string name="permission_scope_www.googleapis.com_auth_books">Управление своими книгами</string>
<string name="permission_scope_www.googleapis.com_auth_calendar">Управление своими календарями</string>
<string name="permission_scope_www.googleapis.com_auth_calendar.readonly">Посмотр своих календарей</string>
<string name="permission_scope_www.googleapis.com_auth_calendar.readonly">Просмотр своих календарей</string>
<string name="permission_scope_www.googleapis.com_auth_cloudprint">Просмотр и управление своими данными Google Cloud Print</string>
<string name="permission_scope_www.googleapis.com_auth_compute.readonly">Посмотр своих ресурсов Google Compute Engine</string>
<string name="permission_scope_www.googleapis.com_auth_compute.readonly">Просмотр своих ресурсов Google Compute Engine</string>
<string name="permission_scope_www.googleapis.com_auth_compute">Просмотр и управление своими ресурсами Google Compute Engine</string>
<string name="permission_scope_www.googleapis.com_auth_coordinate.readonly">Посмотр своих целей Google Coordinate</string>
<string name="permission_scope_www.googleapis.com_auth_coordinate.readonly">Просмотр своих целей Google Coordinate</string>
<string name="permission_scope_www.googleapis.com_auth_coordinate">Просмотр и управление своими задаными координатами Google Maps</string>
<string name="permission_scope_www.googleapis.com_auth_devstorage.full_control">Управление своими данными и разрешениями в Google Cloud Storage</string>
<string name="permission_scope_www.googleapis.com_auth_devstorage.read_only">Просмотр своих данных в Google Cloud Storage</string>
@ -128,14 +128,14 @@
<string name="permission_scope_www.googleapis.com_auth_drive.apps.readonly">Посмотреть свои приложения Google Drive</string>
<string name="permission_scope_www.googleapis.com_auth_drive.file">Просмотр и управление файлами Google Drive, которые вы открыли или создали в этом приложении</string>
<string name="permission_scope_www.googleapis.com_auth_drive.install">Особые возможности, позволяющие пользователям одобрить установку приложения</string>
<string name="permission_scope_www.googleapis.com_auth_drive.metadata.readonly">Посмотр метаданных для файлов и документов Google Drive</string>
<string name="permission_scope_www.googleapis.com_auth_drive.readonly">Посмотр файлов и документов Google Drive</string>
<string name="permission_scope_www.googleapis.com_auth_drive.metadata.readonly">Просмотр метаданных для файлов и документов Google Drive</string>
<string name="permission_scope_www.googleapis.com_auth_drive.readonly">Просмотр файлов и документов Google Drive</string>
<string name="permission_scope_www.googleapis.com_auth_drive.scripts">"Измениение поведения своих сценариев Google Apps Script"</string>
<string name="permission_scope_www.googleapis.com_auth_drive">Просмотр и управление файлами и документами Google Drive</string>
<string name="permission_scope_www.googleapis.com_auth_freebase.readonly">посмотр своей учетной записи Freebase</string>
<string name="permission_scope_www.googleapis.com_auth_freebase.readonly">просмотр своей учетной записи Freebase</string>
<string name="permission_scope_www.googleapis.com_auth_freebase">Зарегистрироваться в Freebase с вашей учетной записью</string>
<string name="permission_scope_www.googleapis.com_auth_fusiontables">Управление слиянием таблиц</string>
<string name="permission_scope_www.googleapis.com_auth_fusiontables.readonly">Посмотр таблицы Fusion</string>
<string name="permission_scope_www.googleapis.com_auth_fusiontables.readonly">Просмотр таблицы Fusion</string>
<string name="permission_scope_www.googleapis.com_auth_games"> Доступа к данным Google Play Игры.</string>
<string name="permission_scope_www.googleapis.com_auth_gan">Управление данными GAN</string>
<string name="permission_scope_www.googleapis.com_auth_gan.readonly">Просмотр данных GAN</string>
@ -156,7 +156,7 @@
<string name="permission_scope_www.googleapis.com_auth_plus.login">"Узнать ваше имя, базовую информацию, и список людей, с которыми вы общаетесь в Google+"</string>
<string name="permission_scope_www.googleapis.com_auth_plus.me">Узнать кто вы в Google</string>
<string name="permission_scope_www.googleapis.com_auth_prediction">Управление своими данными в Google Prediction API</string>
<string name="permission_scope_www.googleapis.com_auth_shoppingapi">Посмотр данных продукта</string>
<string name="permission_scope_www.googleapis.com_auth_shoppingapi">Просмотр данных продукта</string>
<string name="permission_scope_www.googleapis.com_auth_siteverification">Управление вашим списком сайтов и доменов</string>
<string name="permission_scope_www.googleapis.com_auth_siteverification.verify_only">Управление верификацией ваших сайтов в Google</string>
<string name="permission_scope_www.googleapis.com_auth_structuredcontent">Доступ на запись/чтение для Shopping Content API.</string>
@ -170,9 +170,9 @@
<string name="permission_scope_www.googleapis.com_auth_userinfo.profile">Просмотр основной информации об аккаунте</string>
<string name="permission_scope_www.googleapis.com_auth_youtube">Управление аккаунтом YouTube</string>
<string name="permission_scope_www.googleapis.com_auth_youtubepartner">Просматр и управлени своими активами и контентом на YouTube</string>
<string name="permission_scope_www.googleapis.com_auth_youtube.readonly">Посматр своего аккаунта YouTube</string>
<string name="permission_scope_www.googleapis.com_auth_youtube.readonly">Просмотр своего аккаунта YouTube</string>
<string name="permission_scope_www.googleapis.com_auth_youtube.upload">Управление вашими видео на YouTube</string>
<string name="permission_scope_www.googleapis.com_auth_yt_analytics_monetary.readonly">Простор на YouTube аналитики валютного отчеты для вашего контента YouTube</string>
<string name="permission_scope_www.googleapis.com_auth_yt_analytics.readonly">Простотр на YouTube аналитических отчетов для вашего контента YouTube</string>
</resources>
</resources>

View File

@ -16,7 +16,8 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="gms_app_name">microG Services Core</string>
<string name="gms_settings_name">MicroG</string>
<string name="gms_settings_name">Настройки MicroG</string>
<string name="gms_settings_summary">Конфигурирование сервисов microG.</string>
<string name="just_a_sec">Пожалуйста, подождите...</string>
<string name="google_account_label">Google</string>
@ -83,15 +84,15 @@
<!-- Self check -->
<string name="self_check_cat_fake_sig">Поддержка подделки подписи</string>
<string name="self_check_cat_fake_sig">Поддержка подмены подписи</string>
<string name="self_check_cat_gms_packages">Установленные пакеты</string>
<string name="self_check_cat_system">Система</string>
<string name="self_check_name_fake_sig_perm">Система поддерживает подделку подписи:</string>
<string name="self_check_resolution_fake_sig_perm">Ваша прошивка не имеет нативной поддержки подделки подписи. Вы можете использовать Xposed или другие методы, чтобы активировать подделку подписи. Пожалуйста, ознакомьтесь с документацией, какая прошивка поддерживает подделку подписи и как использовать microG в прошивке, которая не поддерживает.</string>
<string name="self_check_name_perm_granted">Система предоставляет разрешение подделки подписи:</string>
<string name="self_check_resolution_perm_granted">Ваша прошивка поддерживает подделку подписи, но требует дополнительных действий для ее активации. Пожалуйста, ознакомьтесь с документацией, где описано что нужно сделать.</string>
<string name="self_check_name_system_spoofs">Система подделывает подписи:</string>
<string name="self_check_name_fake_sig_perm">Система поддерживает подмену подписи:</string>
<string name="self_check_resolution_fake_sig_perm">Ваша прошивка не имеет нативной поддержки подмены подписи. Вы можете использовать Xposed или другие методы, чтобы активировать подмену подписи. Пожалуйста, ознакомьтесь с документацией, какая прошивка поддерживает подмену подписи и как использовать microG в прошивке, которая не поддерживает.</string>
<string name="self_check_name_perm_granted">Система разрешает подмену подписи:</string>
<string name="self_check_resolution_perm_granted">Ваша прошивка поддерживает подмену подписи, но требует дополнительных действий для ее активации. Пожалуйста, ознакомьтесь с документацией, где описано что нужно сделать.</string>
<string name="self_check_name_system_spoofs">Система подменяет подписи:</string>
<string name="self_check_resolution_system_spoofs">Пожалуйста, ознакомьтесь с документацией, где описано что нужно сделать.</string>
<string name="self_check_pkg_gms">Play Services (GmsCore)</string>
@ -100,7 +101,7 @@
<string name="self_check_name_app_installed"><xliff:g example="F-Droid">%1$s</xliff:g> установлен: </string>
<string name="self_check_resolution_app_installed">Установите приложение <xliff:g example="F-Droid">%1$s</xliff:g> или совместимое. Пожалуйста, ознакомьтесь с документацией, где описано какие приложения совместимы.</string>
<string name="self_check_name_correct_sig"><xliff:g example="F-Droid">%1$s</xliff:g> имеет правильную подпись: </string>
<string name="self_check_resolution_correct_sig">Либо установленный <xliff:g example="F-Droid">%1$s</xliff:g> не совместим, либо подделка подписи не активна для него. Пожалуйста, ознакомьтесь с документацией, где описано какие приложения или прошивки совместимы.</string>
<string name="self_check_resolution_correct_sig">Либо установленный <xliff:g example="F-Droid">%1$s</xliff:g> не совместим, либо подмена подписи не активна для него. Пожалуйста, ознакомьтесь с документацией, где описано какие приложения или прошивки совместимы.</string>
<string name="self_check_name_battery_optimizations">Оптимизация энергопотребления отключена:</string>
<string name="self_check_resolution_battery_optimizations">Нажмите здесь, чтобы разрешить приложению работать в фоне. Без этого некоторые приложения могут работать со сбоями</string>
@ -169,7 +170,7 @@
<string name="pref_snet_status_third_party_summary">Сторонние сервера могут быть в состоянии ответить на запросы SafetyNet без подписи DroidGuard</string>
<string name="pref_snet_custom_url_title">URL стороннего сервера</string>
<string name="pref_snet_custom_url_summary">Полный URL стороннего сервера, который отвечает на проверочные запросы SafetyNet</string>
<string name="pref_snet_self_signed_title">Создавать сертификат самому</string>
<string name="pref_snet_self_signed_title">Создавать сертификат самому</string>
<string name="pref_snet_self_signed_summary">Вместо запросов на сервер подписывать SafetyNet локально, используя самостоятельно созданный сертификат. Большинство приложений будут отказываться использовать самоподписанные ответы.</string>
</resources>
</resources>

View File

@ -17,6 +17,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="gms_app_name">microG Services Core</string>
<string name="gms_settings_name">microG Settings</string>
<string name="gms_settings_summary">Setup microG services Core.</string>
<string name="just_a_sec">Just a sec…</string>
<string name="google_account_label">Google</string>
@ -165,11 +166,14 @@ This can take a couple of minutes."</string>
<string name="pref_snet_status_official_title">Use official server</string>
<string name="pref_snet_status_official_summary">Requires an unrooted system and microG DroidGuard Helper installed</string>
<string name="pref_snet_status_official_info">official server</string>
<string name="pref_snet_status_third_party_title">Use third-party server</string>
<string name="pref_snet_status_third_party_summary">Third-party servers might be able to reply to SafetyNet requests without DroidGuard signature</string>
<string name="pref_snet_status_third_party_info">third-party server</string>
<string name="pref_snet_custom_url_title">Custom server URL</string>
<string name="pref_snet_custom_url_summary">Full URL of the third-party server answering SafetyNet attestation requests</string>
<string name="pref_snet_self_signed_title">Use self-signed certificate</string>
<string name="pref_snet_self_signed_summary">Instead of requesting a server, sign SafetyNet responses locally using a self-signed certificate. Most apps will refuse to use self-signed responses.</string>
<string name="pref_snet_status_self_signed_info">self-signed certificate</string>
</resources>