Squashed commit:

- Update build tools
- Update sublibs
- Add proper PlacePicker, fixes #65
- Add selfcheck
- Improvements to MCS connection, related #31 #54
- Do not crash when permission to GPS is not granted
- Various smaller fixes
This commit is contained in:
Marvin W 2016-01-12 23:27:43 +01:00
parent affce9dc23
commit 8fa0515bf6
48 changed files with 951 additions and 342 deletions

2
extern/GmsApi vendored

@ -1 +1 @@
Subproject commit 8d39059ce60908519a4642562c848d9da063e710
Subproject commit 865b41664d6afabecddbd1a5d1b7c702d0bd821f

2
extern/UnifiedNlp vendored

@ -1 +1 @@
Subproject commit a7755939012f931628e623b3cc55b849f5acdf64
Subproject commit 3b5727c78ab7a997226f2b030d4b168d0b3346a4

Binary file not shown.

1
microg-ui-tools Symbolic link
View File

@ -0,0 +1 @@
extern/UnifiedNlp/microg-ui-tools/

View File

@ -19,7 +19,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
classpath 'com.android.tools.build:gradle:1.5.0'
}
}
@ -33,13 +33,14 @@ repositories {
}
dependencies {
compile 'com.android.support:support-v4:23.0.1'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'de.hdodenhof:circleimageview:1.2.1'
compile 'com.squareup.wire:wire-runtime:1.6.1'
compile project(":microg-ui-tools")
compile project(':play-services-api')
compile project(':unifiednlp-base')
compile project(':wearable-lib')
// vtm from ./libs
compile 'org.oscim:vtm-android:0.6.0-SNAPSHOT@aar'
compile 'org.oscim:vtm-themes:0.6.0-SNAPSHOT@jar'
@ -53,10 +54,34 @@ dependencies {
compile 'org.slf4j:slf4j-android:1.7.6'
}
String getMyVersionName() {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'describe', '--tags', '--always', '--dirty'
standardOutput = stdout
}
return stdout.toString().trim()
}
int getMyVersionCode(String ref) {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-list', '--count', "$ref..HEAD"
standardOutput = stdout
}
return Integer.parseInt(stdout.toString().trim())
}
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
versionName("8.4.89 (microG " + getMyVersionName() + ")")
// Update commit id to current when increasing gms version code
versionCode(8489238 + getMyVersionCode('249c935f'))
}
sourceSets {
main {
java.srcDirs += 'src/main/protos-java'

View File

@ -14,11 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<manifest
package="com.google.android.gms"
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="8489238"
android:versionName="8.4.89 (microG v0.02)">
<manifest package="com.google.android.gms"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk
android:minSdkVersion="14"
@ -57,6 +54,10 @@
android:name="org.microg.gms.STATUS_BROADCAST"
android:label="@string/perm_status_broadcast_label"
android:protectionLevel="normal"/>
<permission
android:name="org.microg.gms.EXTENDED_ACCESS"
android:label="@string/perm_extended_access_label"
android:protectionLevel="dangerous"/>
<uses-permission android:name="android.permission.FAKE_PACKAGE_SIGNATURE"/>
@ -78,6 +79,7 @@
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="com.google.android.c2dm.permission.SEND"/>
<uses-permission android:name="org.microg.gms.STATUS_BROADCAST"/>
<uses-permission android:name="org.microg.gms.EXTENDED_ACCESS"/>
<application
android:allowBackup="false"
@ -208,8 +210,7 @@
android:name="org.microg.gms.maps.data.SharedTileProvider"
android:authorities="org.microg.gms.map.tile"
android:enabled="true"
android:exported="true">
</provider>
android:exported="true"/>
<!-- DroidGuard -->
@ -360,11 +361,6 @@
</intent-filter>
</activity>
<activity
android:name="org.microg.gms.ui.SelfCheckActivity"
android:label="@string/self_check_title"
android:theme="@style/SettingsTheme"/>
<!-- Other -->
<service

View File

@ -22,14 +22,14 @@ import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.dynamic.ObjectWrapper;
import com.google.android.gms.plus.internal.IPlusOneButtonCreator;
import org.microg.gms.common.Constants;
import org.microg.gms.auth.AuthConstants;
import org.microg.gms.plus.PlusOneButtonImpl;
public class PlusOneButtonCreatorImpl extends IPlusOneButtonCreator.Stub {
@Override
public IObjectWrapper create(IObjectWrapper context, int size, int annotation, String url, int activityRequestCode) throws RemoteException {
Context ctx = (Context) ObjectWrapper.unwrap(context);
return ObjectWrapper.wrap(new PlusOneButtonImpl(ctx, size, annotation, url, Constants.DEFAULT_ACCOUNT));
return ObjectWrapper.wrap(new PlusOneButtonImpl(ctx, size, annotation, url, AuthConstants.DEFAULT_ACCOUNT));
}
@Override

View File

@ -16,17 +16,30 @@
package org.microg.gms.auth;
import android.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.android.gms.R;
import org.microg.gms.common.PackageUtils;
import java.util.Arrays;
import static org.microg.gms.auth.AuthConstants.PROVIDER_EXTRA_ACCOUNTS;
import static org.microg.gms.auth.AuthConstants.PROVIDER_EXTRA_CLEAR_PASSWORD;
import static org.microg.gms.auth.AuthConstants.PROVIDER_METHOD_CLEAR_PASSWORD;
import static org.microg.gms.auth.AuthConstants.PROVIDER_METHOD_GET_ACCOUNTS;
public class AccountContentProvider extends ContentProvider {
private static final String TAG = "GmsAuthProvider";
@ -38,13 +51,20 @@ public class AccountContentProvider extends ContentProvider {
@Nullable
@Override
public Bundle call(String method, String arg, Bundle extras) {
// FIXME: Restrict access!
if ("get_accounts".equals(method) && getContext().getString(R.string.google_account_type).equals(arg)) {
if (!PackageUtils.callerHasExtendedAccess(getContext())) {
String[] packagesForUid = getContext().getPackageManager().getPackagesForUid(Binder.getCallingUid());
if (packagesForUid != null && packagesForUid.length != 0)
Log.w(TAG, "Not granting access to " + Arrays.toString(packagesForUid)
+ ", signature: " + PackageUtils.firstSignatureDigest(getContext(), packagesForUid[0]));
if (getContext().checkCallingPermission(Manifest.permission.GET_ACCOUNTS) != PackageManager.PERMISSION_GRANTED)
throw new SecurityException("Access denied, missing GET_ACCOUNTS or EXTENDED_ACCESS permission");
}
if (PROVIDER_METHOD_GET_ACCOUNTS.equals(method) && getContext().getString(R.string.google_account_type).equals(arg)) {
Bundle result = new Bundle();
result.putParcelableArray("accounts", AccountManager.get(getContext()).getAccountsByType(arg));
result.putParcelableArray(PROVIDER_EXTRA_ACCOUNTS, AccountManager.get(getContext()).getAccountsByType(arg));
return result;
} else if ("clear_password".equals(method)) {
Account a = extras.getParcelable("clear_password");
} else if (PROVIDER_METHOD_CLEAR_PASSWORD.equals(method)) {
Account a = extras.getParcelable(PROVIDER_EXTRA_CLEAR_PASSWORD);
AccountManager.get(getContext()).clearPassword(a);
return null;
}

View File

@ -25,7 +25,6 @@ import android.util.Log;
import com.google.android.gms.R;
import org.microg.gms.common.Constants;
import org.microg.gms.common.PackageUtils;
import java.io.IOException;
@ -180,7 +179,7 @@ public class AuthManager {
}
public AuthResponse requestAuth(boolean legacy) throws IOException {
if (service.equals(Constants.SCOPE_GET_ACCOUNT_ID)) {
if (service.equals(AuthConstants.SCOPE_GET_ACCOUNT_ID)) {
AuthResponse response = new AuthResponse();
response.accountId = response.auth = getAccountManager().getUserData(getAccount(), "GoogleUserId");
return response;

View File

@ -20,12 +20,35 @@ import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Binder;
import com.google.android.gms.Manifest;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import static org.microg.gms.common.Constants.GMS_PACKAGE_SIGNATURE_SHA1;
public class PackageUtils {
private static final String[] KNOWN_GOOGLE_SIGNATURES = {GMS_PACKAGE_SIGNATURE_SHA1};
public static boolean isGoogleSignedPackages(Context context, String packageName) {
return Arrays.asList(KNOWN_GOOGLE_SIGNATURES).contains(firstSignatureDigest(context, packageName));
}
public static void assertExtendedAccess(Context context) {
if (!callerHasExtendedAccess(context))
throw new SecurityException("Access denied, missing EXTENDED_ACCESS permission");
}
public static boolean callerHasExtendedAccess(Context context) {
String[] packagesForUid = context.getPackageManager().getPackagesForUid(Binder.getCallingUid());
return (packagesForUid != null && packagesForUid.length != 0 && isGoogleSignedPackages(context, packagesForUid[0])) ||
context.checkCallingPermission(Manifest.permission.EXTENDED_ACCESS) == PackageManager.PERMISSION_GRANTED;
}
public static void checkPackageUid(Context context, String packageName, int callingUid) {
String[] packagesForUid = context.getPackageManager().getPackagesForUid(callingUid);
if (packagesForUid != null && !Arrays.asList(packagesForUid).contains(packageName)) {

View File

@ -16,7 +16,12 @@
package org.microg.gms.common;
import android.Manifest;
import android.content.Context;
import android.support.v4.content.ContextCompat;
import android.widget.Toast;
import com.google.android.gms.R;
import org.microg.gms.checkin.LastCheckinInfo;
@ -25,6 +30,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
public class Utils {
public static String getAndroidIdHex(Context context) {
return Long.toHexString(LastCheckinInfo.read(context).androidId);
@ -38,6 +45,14 @@ public class Utils {
return new Build();
}
public static boolean hasSelfPermissionOrNotify(Context context, String permission) {
if (ContextCompat.checkSelfPermission(context, permission) != PERMISSION_GRANTED) {
Toast.makeText(context, context.getString(R.string.lacking_permission_toast, permission), Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
public static byte[] readStreamToEnd(final InputStream is) throws IOException {
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
if (is != null) {

View File

@ -16,7 +16,7 @@
package org.microg.gms.gcm;
public class Constants {
public final class McsConstants {
public static final int MCS_HEARTBEAT_PING_TAG = 0;
public static final int MCS_HEARTBEAT_ACK_TAG = 1;
public static final int MCS_LOGIN_REQUEST_TAG = 2;
@ -32,6 +32,7 @@ public class Constants {
public static final int MSG_OUTPUT = 20;
public static final int MSG_OUTPUT_ERROR = 21;
public static final int MSG_OUTPUT_READY = 22;
public static final int MSG_OUTPUT_DONE = 23;
public static final int MSG_TEARDOWN = 30;
public static final int MSG_CONNECT = 40;
public static final int MSG_HEARTBEAT = 41;

View File

@ -33,16 +33,16 @@ import org.microg.gms.gcm.mcs.LoginResponse;
import java.io.IOException;
import java.io.InputStream;
import static org.microg.gms.gcm.Constants.MCS_CLOSE_TAG;
import static org.microg.gms.gcm.Constants.MCS_DATA_MESSAGE_STANZA_TAG;
import static org.microg.gms.gcm.Constants.MCS_HEARTBEAT_ACK_TAG;
import static org.microg.gms.gcm.Constants.MCS_HEARTBEAT_PING_TAG;
import static org.microg.gms.gcm.Constants.MCS_IQ_STANZA_TAG;
import static org.microg.gms.gcm.Constants.MCS_LOGIN_REQUEST_TAG;
import static org.microg.gms.gcm.Constants.MCS_LOGIN_RESPONSE_TAG;
import static org.microg.gms.gcm.Constants.MSG_INPUT;
import static org.microg.gms.gcm.Constants.MSG_INPUT_ERROR;
import static org.microg.gms.gcm.Constants.MSG_TEARDOWN;
import static org.microg.gms.gcm.McsConstants.MCS_CLOSE_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_DATA_MESSAGE_STANZA_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_ACK_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_PING_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_IQ_STANZA_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_LOGIN_REQUEST_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_LOGIN_RESPONSE_TAG;
import static org.microg.gms.gcm.McsConstants.MSG_INPUT;
import static org.microg.gms.gcm.McsConstants.MSG_INPUT_ERROR;
import static org.microg.gms.gcm.McsConstants.MSG_TEARDOWN;
public class McsInputStream extends Thread {
private static final String TAG = "GmsGcmMcsInput";
@ -71,10 +71,9 @@ public class McsInputStream extends Thread {
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
Message msg = read();
Log.d(TAG, "Incoming message: " + msg);
android.os.Message msg = read();
if (msg != null) {
mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_INPUT, msg));
mainHandler.dispatchMessage(msg);
} else {
mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_TEARDOWN, "null message"));
}
@ -118,7 +117,7 @@ public class McsInputStream extends Thread {
}
}
public synchronized Message read() throws IOException {
public synchronized android.os.Message read() throws IOException {
ensureVersionRead();
int mcsTag = is.read();
int mcsSize = readVarint();
@ -132,8 +131,10 @@ public class McsInputStream extends Thread {
len += (read = is.read(bytes, len, mcsSize - len)) < 0 ? 0 : read;
}
Message message = read(mcsTag, bytes, len);
if (message == null) return null;
Log.d(TAG, "Incoming message: " + message);
streamId++;
return message;
return mainHandler.obtainMessage(MSG_INPUT, mcsTag, streamId, message);
}
private static Message read(int mcsTag, byte[] bytes, int len) throws IOException {

View File

@ -30,15 +30,16 @@ import org.microg.gms.gcm.mcs.LoginRequest;
import java.io.IOException;
import java.io.OutputStream;
import static org.microg.gms.gcm.Constants.MCS_DATA_MESSAGE_STANZA_TAG;
import static org.microg.gms.gcm.Constants.MCS_HEARTBEAT_ACK_TAG;
import static org.microg.gms.gcm.Constants.MCS_HEARTBEAT_PING_TAG;
import static org.microg.gms.gcm.Constants.MCS_LOGIN_REQUEST_TAG;
import static org.microg.gms.gcm.Constants.MCS_VERSION_CODE;
import static org.microg.gms.gcm.Constants.MSG_OUTPUT;
import static org.microg.gms.gcm.Constants.MSG_OUTPUT_ERROR;
import static org.microg.gms.gcm.Constants.MSG_OUTPUT_READY;
import static org.microg.gms.gcm.Constants.MSG_TEARDOWN;
import static org.microg.gms.gcm.McsConstants.MCS_DATA_MESSAGE_STANZA_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_ACK_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_PING_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_LOGIN_REQUEST_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_VERSION_CODE;
import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT;
import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_DONE;
import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_ERROR;
import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_READY;
import static org.microg.gms.gcm.McsConstants.MSG_TEARDOWN;
public class McsOutputStream extends Thread implements Handler.Callback {
private static final String TAG = "GmsGcmMcsOutput";
@ -79,19 +80,9 @@ public class McsOutputStream extends Thread implements Handler.Callback {
switch (msg.what) {
case MSG_OUTPUT:
try {
Message message = (Message) msg.obj;
Log.d(TAG, "Outgoing message: " + message);
if (msg.obj instanceof DataMessageStanza) {
writeInternal(message, MCS_DATA_MESSAGE_STANZA_TAG);
} else if (msg.obj instanceof LoginRequest) {
writeInternal(message, MCS_LOGIN_REQUEST_TAG);
} else if (msg.obj instanceof HeartbeatAck) {
writeInternal(message, MCS_HEARTBEAT_ACK_TAG);
} else if (msg.obj instanceof HeartbeatPing) {
writeInternal(message, MCS_HEARTBEAT_PING_TAG);
} else {
Log.w(TAG, "Unknown message: " + msg.obj);
}
Log.d(TAG, "Outgoing message: " + msg.obj);
writeInternal((Message) msg.obj, msg.arg1);
mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_OUTPUT_DONE, msg.arg1, msg.arg2, msg.obj));
} catch (IOException e) {
mainHandler.dispatchMessage(mainHandler.obtainMessage(MSG_OUTPUT_ERROR, e));
}

View File

@ -22,6 +22,8 @@ import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@ -47,22 +49,34 @@ import org.microg.gms.gcm.mcs.Setting;
import java.net.Socket;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.net.ssl.SSLContext;
import static android.os.Build.VERSION.SDK_INT;
import static org.microg.gms.gcm.Constants.ACTION_CONNECT;
import static org.microg.gms.gcm.Constants.ACTION_HEARTBEAT;
import static org.microg.gms.gcm.Constants.ACTION_RECONNECT;
import static org.microg.gms.gcm.Constants.EXTRA_REASON;
import static org.microg.gms.gcm.Constants.MSG_CONNECT;
import static org.microg.gms.gcm.Constants.MSG_HEARTBEAT;
import static org.microg.gms.gcm.Constants.MSG_INPUT;
import static org.microg.gms.gcm.Constants.MSG_INPUT_ERROR;
import static org.microg.gms.gcm.Constants.MSG_OUTPUT;
import static org.microg.gms.gcm.Constants.MSG_OUTPUT_ERROR;
import static org.microg.gms.gcm.Constants.MSG_OUTPUT_READY;
import static org.microg.gms.gcm.Constants.MSG_TEARDOWN;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_RECEIVE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_FROM;
import static org.microg.gms.gcm.GcmConstants.EXTRA_MESSAGE_TYPE;
import static org.microg.gms.gcm.GcmConstants.MESSAGE_TYPE_GCM;
import static org.microg.gms.gcm.McsConstants.ACTION_CONNECT;
import static org.microg.gms.gcm.McsConstants.ACTION_HEARTBEAT;
import static org.microg.gms.gcm.McsConstants.ACTION_RECONNECT;
import static org.microg.gms.gcm.McsConstants.EXTRA_REASON;
import static org.microg.gms.gcm.McsConstants.MCS_CLOSE_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_DATA_MESSAGE_STANZA_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_ACK_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_HEARTBEAT_PING_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_LOGIN_REQUEST_TAG;
import static org.microg.gms.gcm.McsConstants.MCS_LOGIN_RESPONSE_TAG;
import static org.microg.gms.gcm.McsConstants.MSG_CONNECT;
import static org.microg.gms.gcm.McsConstants.MSG_HEARTBEAT;
import static org.microg.gms.gcm.McsConstants.MSG_INPUT;
import static org.microg.gms.gcm.McsConstants.MSG_INPUT_ERROR;
import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT;
import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_DONE;
import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_ERROR;
import static org.microg.gms.gcm.McsConstants.MSG_OUTPUT_READY;
import static org.microg.gms.gcm.McsConstants.MSG_TEARDOWN;
public class McsService extends Service implements Handler.Callback {
private static final String TAG = "GmsGcmMcsSvc";
@ -78,6 +92,8 @@ public class McsService extends Service implements Handler.Callback {
public static final int SERVICE_PORT = 5228;
private static final String PREF_GCM_HEARTBEAT = "gcm_heartbeat_interval";
private static final int WAKELOCK_TIMEOUT = 5000;
public static int heartbeatMs = 60000;
private static long lastHeartbeatAckElapsedRealtime = -1;
@ -185,9 +201,9 @@ public class McsService extends Service implements Handler.Callback {
updateHeartbeatMs();
synchronized (McsService.class) {
if (rootHandler != null) {
wakeLock.acquire(5000);
Object reason = intent == null ? "I am so sticky!" :
intent.hasExtra(EXTRA_REASON) ? intent.getExtras().get(EXTRA_REASON) : intent;
if (intent == null) return START_REDELIVER_INTENT;
wakeLock.acquire(WAKELOCK_TIMEOUT);
Object reason = intent.hasExtra(EXTRA_REASON) ? intent.getExtras().get(EXTRA_REASON) : intent;
if (ACTION_CONNECT.equals(intent.getAction())) {
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_CONNECT, reason));
} else if (ACTION_HEARTBEAT.equals(intent.getAction())) {
@ -258,7 +274,7 @@ public class McsService extends Service implements Handler.Callback {
if (inputStream.newStreamIdAvailable()) {
ack.last_stream_id_received(inputStream.getStreamId());
}
send(ack.build());
send(MCS_HEARTBEAT_ACK_TAG, ack.build());
}
private void handleHeartbeatAck(HeartbeatAck ack) {
@ -286,13 +302,20 @@ public class McsService extends Service implements Handler.Callback {
private void handleAppMessage(DataMessageStanza msg) {
Intent intent = new Intent();
intent.setAction("com.google.android.c2dm.intent.RECEIVE");
intent.setAction(ACTION_C2DM_RECEIVE);
intent.addCategory(msg.category);
intent.putExtra("from", msg.from);
intent.putExtra(EXTRA_MESSAGE_TYPE, MESSAGE_TYPE_GCM);
intent.putExtra(EXTRA_FROM, msg.from);
for (AppData appData : msg.app_data) {
intent.putExtra(appData.key, appData.value);
}
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
// FIXME: #75
List<ResolveInfo> infos = getPackageManager().queryBroadcastReceivers(intent, PackageManager.GET_RESOLVED_FILTER);
for (ResolveInfo resolveInfo : infos)
Log.d(TAG, "Target: " + resolveInfo);
if (infos.isEmpty())
Log.d(TAG, "No target for message, wut?");
sendOrderedBroadcast(intent, msg.category + ".permission.C2D_MESSAGE");
}
@ -308,7 +331,7 @@ public class McsService extends Service implements Handler.Callback {
if (inputStream.newStreamIdAvailable()) {
msgResponse.last_stream_id_received(inputStream.getStreamId());
}
send(msgResponse.build());
send(MCS_DATA_MESSAGE_STANZA_TAG, msgResponse.build());
}
}
}
@ -317,16 +340,16 @@ public class McsService extends Service implements Handler.Callback {
return getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
}
private void send(Message message) {
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_OUTPUT, message));
private void send(int type, Message message) {
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_OUTPUT, type, 0, message));
}
private void sendOutputStream(int what, Object obj) {
private void sendOutputStream(int what, int arg, Object obj) {
McsOutputStream os = outputStream;
if (os != null) {
Handler outputHandler = os.getHandler();
if (outputHandler != null)
outputHandler.sendMessage(outputHandler.obtainMessage(what, obj));
outputHandler.sendMessage(outputHandler.obtainMessage(what, arg, 0, obj));
}
}
@ -334,10 +357,10 @@ public class McsService extends Service implements Handler.Callback {
public boolean handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_INPUT:
handleInput((Message) msg.obj);
handleInput(msg.arg1, (Message) msg.obj);
return true;
case MSG_OUTPUT:
sendOutputStream(MSG_OUTPUT, msg.obj);
sendOutputStream(MSG_OUTPUT, msg.arg1, msg.obj);
return true;
case MSG_INPUT_ERROR:
case MSG_OUTPUT_ERROR:
@ -361,7 +384,7 @@ public class McsService extends Service implements Handler.Callback {
if (inputStream.newStreamIdAvailable()) {
ping.last_stream_id_received(inputStream.getStreamId());
}
send(ping.build());
send(MCS_HEARTBEAT_PING_TAG, ping.build());
scheduleHeartbeat(this);
} else {
Log.d(TAG, "Ignoring heartbeat, not connected!");
@ -370,27 +393,45 @@ public class McsService extends Service implements Handler.Callback {
return true;
case MSG_OUTPUT_READY:
Log.d(TAG, "Sending login request...");
send(buildLoginRequest());
send(MCS_LOGIN_REQUEST_TAG, buildLoginRequest());
return true;
case MSG_OUTPUT_DONE:
handleOutputDone(msg);
return true;
}
Log.w(TAG, "Unknown message: " + msg);
return false;
}
private void handleInput(Message message) {
private void handleOutputDone(android.os.Message msg) {
switch (msg.arg1) {
case MCS_HEARTBEAT_PING_TAG:
wakeLock.release();
break;
default:
}
}
private void handleInput(int type, Message message) {
try {
if (message instanceof DataMessageStanza) {
handleCloudMessage((DataMessageStanza) message);
} else if (message instanceof HeartbeatPing) {
handleHearbeatPing((HeartbeatPing) message);
} else if (message instanceof Close) {
handleClose((Close) message);
} else if (message instanceof LoginResponse) {
handleLoginResponse((LoginResponse) message);
} else if (message instanceof HeartbeatAck) {
handleHeartbeatAck((HeartbeatAck) message);
} else {
Log.w(TAG, "Unknown message: " + message);
switch (type) {
case MCS_DATA_MESSAGE_STANZA_TAG:
handleCloudMessage((DataMessageStanza) message);
break;
case MCS_HEARTBEAT_PING_TAG:
handleHearbeatPing((HeartbeatPing) message);
break;
case MCS_HEARTBEAT_ACK_TAG:
handleHeartbeatAck((HeartbeatAck) message);
break;
case MCS_CLOSE_TAG:
handleClose((Close) message);
break;
case MCS_LOGIN_RESPONSE_TAG:
handleLoginResponse((LoginResponse) message);
break;
default:
Log.w(TAG, "Unknown message: " + message);
}
resetCurrentDelay();
} catch (Exception e) {
@ -399,7 +440,7 @@ public class McsService extends Service implements Handler.Callback {
}
private void handleTeardown(android.os.Message msg) {
sendOutputStream(MSG_TEARDOWN, msg.obj);
sendOutputStream(MSG_TEARDOWN, msg.arg1, msg.obj);
if (inputStream != null) {
inputStream.close();
inputStream = null;
@ -413,7 +454,10 @@ public class McsService extends Service implements Handler.Callback {
alarmManager.cancel(heartbeatIntent);
if (wakeLock != null) {
wakeLock.release();
try {
wakeLock.release();
} catch (Exception ignored) {
}
}
}
}

View File

@ -32,11 +32,24 @@ import org.microg.gms.common.Utils;
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;
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;
import static org.microg.gms.gcm.GcmConstants.EXTRA_MESSENGER;
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";
private static final String REMOVED = "%%REMOVED%%";
private static final String ERROR = "%%ERROR%%";
private static final String GCM_REGISTRATION_PREF = "gcm_registrations";
public PushRegisterService() {
super(TAG);
@ -44,19 +57,17 @@ public class PushRegisterService extends IntentService {
}
private SharedPreferences getSharedPreferences() {
return getSharedPreferences("gcm_registrations", MODE_PRIVATE);
return getSharedPreferences(GCM_REGISTRATION_PREF, MODE_PRIVATE);
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent: " + intent);
try {
if (intent != null && intent.getAction() != null) {
if (intent.getAction().equalsIgnoreCase("com.google.android.c2dm.intent.REGISTER")) {
register(intent);
} else if (intent.getAction().equalsIgnoreCase("com.google.android.c2dm.intent.UNREGISTER")) {
unregister(intent);
}
if (ACTION_C2DM_REGISTER.equals(intent.getAction())) {
register(intent);
} else if (ACTION_C2DM_UNREGISTER.equals(intent.getAction())) {
unregister(intent);
}
} catch (Exception e) {
Log.w(TAG, e);
@ -73,27 +84,27 @@ public class PushRegisterService extends IntentService {
}
private void register(Intent intent) {
PendingIntent pendingIntent = intent.getParcelableExtra("app");
String sender = intent.getStringExtra("sender");
PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_APP);
String sender = intent.getStringExtra(EXTRA_SENDER);
String app = packageFromPendingIntent(pendingIntent);
Log.d(TAG, "register[res]: " + intent.toString() + " extras=" + intent.getExtras());
Log.d(TAG, "register[req]: " + intent.toString() + " extras=" + intent.getExtras());
Intent outIntent = new Intent("com.google.android.c2dm.intent.REGISTRATION");
Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION);
String appSignature = PackageUtils.firstSignatureDigest(this, app);
String regId = register(this, app, appSignature, sender, null, false).token;
if (regId != null) {
outIntent.putExtra("registration_id", regId);
outIntent.putExtra(EXTRA_REGISTRATION_ID, regId);
getSharedPreferences().edit().putString(app + ":" + appSignature, regId).apply();
} else {
outIntent.putExtra("error", "SERVICE_NOT_AVAILABLE");
outIntent.putExtra(EXTRA_ERROR, ERROR_SERVICE_NOT_AVAILABLE);
getSharedPreferences().edit().putString(app + ":" + appSignature, "-").apply();
}
Log.d(TAG, "register[res]: " + outIntent + " extras=" + outIntent.getExtras());
try {
if (intent.hasExtra("google.messenger")) {
Messenger messenger = intent.getParcelableExtra("google.messenger");
if (intent.hasExtra(EXTRA_MESSENGER)) {
Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);
Message message = Message.obtain();
message.obj = outIntent;
messenger.send(message);
@ -127,35 +138,34 @@ public class PushRegisterService extends IntentService {
}
private void unregister(Intent intent) {
PendingIntent pendingIntent = intent.getParcelableExtra("app");
PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_APP);
String app = packageFromPendingIntent(pendingIntent);
Log.d(TAG, "unregister[res]: " + intent.toString() + " extras=" + intent.getExtras());
Log.d(TAG, "unregister[req]: " + intent.toString() + " extras=" + intent.getExtras());
Intent outIntent = new Intent("com.google.android.c2dm.intent.REGISTRATION");
Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION);
String appSignature = PackageUtils.firstSignatureDigest(this, app);
if (REMOVED.equals(getSharedPreferences().getString(app + ":" + appSignature, null))) {
outIntent.putExtra("unregistered", app);
outIntent.putExtra(EXTRA_UNREGISTERED, app);
} else {
RegisterResponse response = register(this, app, appSignature, null, null, true);
if (!app.equals(response.deleted)) {
outIntent.putExtra("error", "SERVICE_NOT_AVAILABLE");
outIntent.putExtra(EXTRA_ERROR, ERROR_SERVICE_NOT_AVAILABLE);
getSharedPreferences().edit().putString(app + ":" + PackageUtils.firstSignatureDigest(this, app), ERROR).apply();
long retry = 0;
if (response.retryAfter != null && !response.retryAfter.contains(":")) {
outIntent.putExtra("Retry-After", Long.parseLong(response.retryAfter));
outIntent.putExtra(EXTRA_RETRY_AFTER, Long.parseLong(response.retryAfter));
}
} else {
outIntent.putExtra("unregistered", app);
outIntent.putExtra(EXTRA_UNREGISTERED, app);
getSharedPreferences().edit().putString(app + ":" + PackageUtils.firstSignatureDigest(this, app), REMOVED).apply();
}
}
Log.d(TAG, "unregister[res]: " + outIntent.toString() + " extras=" + outIntent.getExtras());
try {
if (intent.hasExtra("google.messenger")) {
Messenger messenger = intent.getParcelableExtra("google.messenger");
if (intent.hasExtra(EXTRA_MESSENGER)) {
Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);
Message message = Message.obtain();
message.obj = outIntent;
messenger.send(message);

View File

@ -26,9 +26,9 @@ import android.util.Log;
import org.microg.gms.checkin.LastCheckinInfo;
import static org.microg.gms.gcm.Constants.ACTION_CONNECT;
import static org.microg.gms.gcm.Constants.ACTION_HEARTBEAT;
import static org.microg.gms.gcm.Constants.EXTRA_REASON;
import static org.microg.gms.gcm.McsConstants.ACTION_CONNECT;
import static org.microg.gms.gcm.McsConstants.ACTION_HEARTBEAT;
import static org.microg.gms.gcm.McsConstants.EXTRA_REASON;
public class TriggerReceiver extends WakefulBroadcastReceiver {
private static final String TAG = "GmsGcmTrigger";

View File

@ -16,15 +16,21 @@
package org.microg.gms.location;
import android.Manifest;
import android.app.PendingIntent;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.support.v4.content.ContextCompat;
import android.widget.Toast;
import com.google.android.gms.R;
import com.google.android.gms.location.ILocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.internal.LocationRequestUpdateData;
import org.microg.gms.common.Utils;
import java.util.ArrayList;
import java.util.List;
@ -41,18 +47,25 @@ public class GoogleLocationManager implements LocationChangeListener {
private static final long SWITCH_ON_FRESHNESS_CLIFF_MS = 30000; // 30 seconds
private static final String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION";
private Context context;
private LocationManager locationManager;
private RealLocationProvider gpsProvider;
private RealLocationProvider networkProvider;
private MockLocationProvider mockProvider;
private List<LocationRequestHelper> currentRequests = new ArrayList<LocationRequestHelper>();
private final Context context;
private final RealLocationProvider gpsProvider;
private final RealLocationProvider networkProvider;
private final MockLocationProvider mockProvider;
private final List<LocationRequestHelper> currentRequests = new ArrayList<LocationRequestHelper>();
public GoogleLocationManager(Context context) {
this.context = context;
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
gpsProvider = new RealLocationProvider(locationManager, GPS_PROVIDER, this);
networkProvider = new RealLocationProvider(locationManager, NETWORK_PROVIDER, this);
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (Utils.hasSelfPermissionOrNotify(context, Manifest.permission.ACCESS_FINE_LOCATION)) {
this.gpsProvider = new RealLocationProvider(locationManager, GPS_PROVIDER, this);
} else {
this.gpsProvider = null;
}
if (Utils.hasSelfPermissionOrNotify(context, Manifest.permission.ACCESS_COARSE_LOCATION)) {
this.networkProvider = new RealLocationProvider(locationManager, NETWORK_PROVIDER, this);
} else {
this.networkProvider = null;
}
mockProvider = new MockLocationProvider(this);
}
@ -64,8 +77,8 @@ public class GoogleLocationManager implements LocationChangeListener {
if (mockProvider.getLocation() != null)
return mockProvider.getLocation();
if (gpsPermission) {
Location network = networkProvider.getLastLocation();
Location gps = gpsProvider.getLastLocation();
Location network = networkProvider == null ? null : networkProvider.getLastLocation();
Location gps = gpsProvider == null ? null : gpsProvider.getLastLocation();
if (network == null)
return gps;
if (gps == null)
@ -74,7 +87,7 @@ public class GoogleLocationManager implements LocationChangeListener {
return gps;
return network;
} else if (networkPermission) {
Location network = networkProvider.getLastLocation();
Location network = networkProvider == null ? null : networkProvider.getLastLocation();
if (network != null && network.getExtras() != null && network.getExtras().getParcelable("no_gps_location") instanceof Location) {
network = network.getExtras().getParcelable("no_gps_location");
}
@ -97,9 +110,9 @@ public class GoogleLocationManager implements LocationChangeListener {
private void requestLocationUpdates(LocationRequestHelper request) {
currentRequests.add(request);
if (request.hasFinePermission && request.locationRequest.getPriority() == PRIORITY_HIGH_ACCURACY)
if (gpsProvider != null && request.hasFinePermission && request.locationRequest.getPriority() == PRIORITY_HIGH_ACCURACY)
gpsProvider.addRequest(request);
if (request.hasCoarsePermission && request.locationRequest.getPriority() != PRIORITY_NO_POWER)
if (networkProvider != null && request.hasCoarsePermission && request.locationRequest.getPriority() != PRIORITY_NO_POWER)
networkProvider.addRequest(request);
}
@ -117,8 +130,8 @@ public class GoogleLocationManager implements LocationChangeListener {
private void removeLocationUpdates(LocationRequestHelper request) {
currentRequests.remove(request);
gpsProvider.removeRequest(request);
networkProvider.removeRequest(request);
if (gpsProvider != null) gpsProvider.removeRequest(request);
if (networkProvider != null) networkProvider.removeRequest(request);
}
public void removeLocationUpdates(ILocationListener listener, String packageName) {

View File

@ -19,7 +19,7 @@ package org.microg.gms.location;
import android.location.Location;
import android.os.Bundle;
import static org.microg.gms.common.Constants.KEY_MOCK_LOCATION;
import static org.microg.gms.location.LocationConstants.KEY_MOCK_LOCATION;
public class MockLocationProvider {
private boolean mockEnabled = false;
@ -44,5 +44,6 @@ public class MockLocationProvider {
}
mockLocation.getExtras().putBoolean(KEY_MOCK_LOCATION, false);
this.mockLocation = mockLocation;
this.changeListener.onLocationChanged();
}
}

View File

@ -27,17 +27,19 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@SuppressWarnings("ResourceType")
public class RealLocationProvider {
public static final String TAG = "GmsLocProviderReal";
private Location lastLocation;
private LocationManager locationManager;
private String name;
private final LocationManager locationManager;
private final String name;
private final AtomicBoolean connected = new AtomicBoolean(false);
private final LocationChangeListener changeListener;
private long connectedMinTime;
private float connectedMinDistance;
private Location lastLocation;
private List<LocationRequestHelper> requests = new ArrayList<LocationRequestHelper>();
private final LocationChangeListener changeListener;
private LocationListener listener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
@ -62,7 +64,7 @@ public class RealLocationProvider {
};
public RealLocationProvider(LocationManager locationManager, String name,
LocationChangeListener changeListener) {
LocationChangeListener changeListener) {
this.locationManager = locationManager;
this.name = name;
this.changeListener = changeListener;
@ -70,13 +72,17 @@ public class RealLocationProvider {
}
private void updateLastLocation() {
lastLocation = locationManager.getLastKnownLocation(name);
Location newLocation = locationManager.getLastKnownLocation(name);
if (newLocation != null) lastLocation = newLocation;
}
public Location getLastLocation() {
if (!connected.get()) {
updateLastLocation();
}
if (lastLocation == null) {
Log.d(TAG, "uh-ok: last location for " + name + " is null!");
}
return lastLocation;
}
@ -102,8 +108,7 @@ public class RealLocationProvider {
float minDistance = Float.MAX_VALUE;
for (LocationRequestHelper request : requests) {
minTime = Math.min(request.locationRequest.getInterval(), minTime);
minDistance = Math
.min(request.locationRequest.getSmallestDesplacement(), minDistance);
minDistance = Math.min(request.locationRequest.getSmallestDesplacement(), minDistance);
}
if (connected.get()) {
if (connectedMinTime != minTime || connectedMinDistance != minDistance) {
@ -112,12 +117,9 @@ public class RealLocationProvider {
Looper.getMainLooper());
}
} else {
locationManager.requestLocationUpdates(name, minTime, minDistance, listener,
Looper.getMainLooper());
locationManager.requestLocationUpdates(name, minTime, minDistance, listener, Looper.getMainLooper());
}
Log.d(TAG,
name + ": requesting location updates. minTime=" + minTime + " minDistance=" +
minDistance);
Log.d(TAG, name + ": requesting location updates. minTime=" + minTime + " minDistance=" + minDistance);
connected.set(true);
connectedMinTime = minTime;
connectedMinDistance = minDistance;

View File

@ -17,88 +17,50 @@
package org.microg.gms.maps;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.view.View;
import com.google.android.gms.R;
import com.google.android.gms.maps.model.CameraPosition;
import org.microg.gms.maps.camera.CameraUpdate;
import org.microg.gms.maps.data.SharedTileCache;
import org.microg.gms.maps.markup.ClearableVectorLayer;
import org.microg.gms.maps.markup.DrawableMarkup;
import org.microg.gms.maps.markup.MarkerItemMarkup;
import org.microg.gms.maps.markup.Markup;
import org.oscim.android.MapView;
import org.oscim.android.canvas.AndroidBitmap;
import org.oscim.core.MapPosition;
import org.oscim.core.Point;
import org.oscim.event.Event;
import org.oscim.event.MotionEvent;
import org.oscim.layers.marker.ItemizedLayer;
import org.oscim.layers.marker.MarkerItem;
import org.oscim.layers.marker.MarkerSymbol;
import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.layers.tile.vector.VectorTileLayer;
import org.oscim.layers.tile.vector.labeling.LabelLayer;
import org.oscim.layers.vector.geometries.Drawable;
import org.oscim.map.Layers;
import org.oscim.map.Map;
import org.oscim.map.Viewport;
import org.oscim.theme.VtmThemes;
import org.oscim.tiling.ITileCache;
import org.oscim.tiling.source.oscimap4.OSciMap4TileSource;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BackendMap implements ItemizedLayer.OnItemGestureListener<MarkerItem>, Map.InputListener {
public class BackendMap implements ItemizedLayer.OnItemGestureListener<MarkerItem>, org.oscim.map.Map.InputListener, org.oscim.map.Map.UpdateListener {
private final static String TAG = "GmsMapBackend";
private final Context context;
private final MapView mapView;
private final LabelLayer labels;
private final BuildingLayer buildings;
private final VectorTileLayer baseLayer;
private final OSciMap4TileSource tileSource;
private final ITileCache cache;
private final ItemizedLayer<MarkerItem> items;
private java.util.Map<String, Markup> markupMap = new HashMap<String, Markup>();
private List<DrawableMarkup> drawableMarkups = new ArrayList<DrawableMarkup>();
private ClearableVectorLayer drawables;
private final BackendMapView mapView;
private final CameraUpdateListener cameraUpdateListener;
private final Map<String, Markup> markupMap = new HashMap<String, Markup>();
private final List<DrawableMarkup> drawableMarkups = new ArrayList<DrawableMarkup>();
private MarkerItemMarkup currentlyDraggedItem;
private float dragLastX = -1;
private float dragLastY = -1;
public BackendMap(Context context, final CameraUpdateListener cameraUpdateListener) {
this.context = context;
mapView = new MapView(new ContextContainer(context));
cache = new SharedTileCache(context);
cache.setCacheSize(512 * (1 << 10));
tileSource = new OSciMap4TileSource();
tileSource.setCache(cache);
baseLayer = mapView.map().setBaseMap(tileSource);
Layers layers = mapView.map().layers();
layers.add(labels = new LabelLayer(mapView.map(), baseLayer));
layers.add(drawables = new ClearableVectorLayer(mapView.map()));
layers.add(buildings = new BuildingLayer(mapView.map(), baseLayer));
layers.add(items = new ItemizedLayer<MarkerItem>(mapView.map(), new MarkerSymbol(new AndroidBitmap(BitmapFactory
.decodeResource(ResourcesContainer.get(), R.drawable.nop)), 0.5F, 1)));
items.setOnItemGestureListener(this);
mapView.map().setTheme(VtmThemes.DEFAULT);
this.cameraUpdateListener = cameraUpdateListener;
mapView = new BackendMapView(new ContextContainer(context));
mapView.items().setOnItemGestureListener(this);
mapView.map().input.bind(this);
mapView.map().events.bind(new Map.UpdateListener() {
@Override
public void onMapEvent(Event event, MapPosition mapPosition) {
cameraUpdateListener.onCameraUpdate(GmsMapsTypeHelper.toCameraPosition(mapPosition));
}
});
mapView.map().events.bind(this);
}
public Viewport getViewport() {
@ -110,23 +72,11 @@ public class BackendMap implements ItemizedLayer.OnItemGestureListener<MarkerIte
}
public void onResume() {
try {
Method onResume = MapView.class.getDeclaredMethod("onResume");
onResume.setAccessible(true);
onResume.invoke(mapView);
} catch (Exception e) {
e.printStackTrace();
}
mapView.onResume();
}
public void onPause() {
try {
Method onPause = MapView.class.getDeclaredMethod("onPause");
onPause.setAccessible(true);
onPause.invoke(mapView);
} catch (Exception e) {
e.printStackTrace();
}
mapView.onPause();
}
public MapPosition getMapPosition() {
@ -138,14 +88,14 @@ public class BackendMap implements ItemizedLayer.OnItemGestureListener<MarkerIte
}
public boolean hasBuilding() {
return mapView.map().layers().contains(buildings);
return mapView.map().layers().contains(mapView.buildings());
}
public void setBuildings(boolean buildingsEnabled) {
if (!hasBuilding() && buildingsEnabled) {
mapView.map().layers().add(buildings);
mapView.map().layers().add(mapView.buildings());
} else if (hasBuilding() && !buildingsEnabled) {
mapView.map().layers().remove(buildings);
mapView.map().layers().remove(mapView.buildings());
}
redraw();
}
@ -181,11 +131,11 @@ public class BackendMap implements ItemizedLayer.OnItemGestureListener<MarkerIte
}
private synchronized void updateDrawableLayer() {
drawables.clear();
mapView.drawables().clear();
for (DrawableMarkup markup : drawableMarkups) {
Drawable drawable = markup.getDrawable(mapView.map());
if (drawable != null) {
drawables.add(drawable);
mapView.drawables().add(drawable);
}
}
}
@ -193,27 +143,27 @@ public class BackendMap implements ItemizedLayer.OnItemGestureListener<MarkerIte
public synchronized <T extends MarkerItemMarkup> T add(T markup) {
if (markup == null) return null;
markupMap.put(markup.getId(), markup);
items.addItem(markup.getMarkerItem(context));
mapView.items().addItem(markup.getMarkerItem(context));
redraw();
return markup;
}
public synchronized void clear() {
markupMap.clear();
items.removeAllItems();
mapView.items().removeAllItems();
drawableMarkups.clear();
drawables.clear();
mapView.drawables().clear();
redraw();
}
public synchronized void remove(Markup markup) {
if (markup instanceof MarkerItemMarkup) {
markupMap.remove(markup.getId());
items.removeItem(items.getByUid(markup.getId()));
mapView.items().removeItem(mapView.items().getByUid(markup.getId()));
} else if (markup instanceof DrawableMarkup) {
drawableMarkups.remove(markup);
updateDrawableLayer();
drawables.update();
mapView.drawables().update();
}
redraw();
}
@ -221,11 +171,11 @@ public class BackendMap implements ItemizedLayer.OnItemGestureListener<MarkerIte
public synchronized void update(Markup markup) {
if (markup == null) return;
if (markup instanceof MarkerItemMarkup) {
items.removeItem(items.getByUid(markup.getId()));
items.addItem(((MarkerItemMarkup) markup).getMarkerItem(context));
mapView.items().removeItem(mapView.items().getByUid(markup.getId()));
mapView.items().addItem(((MarkerItemMarkup) markup).getMarkerItem(context));
} else if (markup instanceof DrawableMarkup) {
updateDrawableLayer();
drawables.update();
mapView.drawables().update();
}
redraw();
}
@ -292,6 +242,11 @@ public class BackendMap implements ItemizedLayer.OnItemGestureListener<MarkerIte
mapView.map().getEventLayer().enableTilt(enabled);
}
@Override
public void onMapEvent(Event event, MapPosition mapPosition) {
cameraUpdateListener.onCameraUpdate(GmsMapsTypeHelper.toCameraPosition(mapPosition));
}
public interface CameraUpdateListener {
void onCameraUpdate(CameraPosition cameraPosition);
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2013-2016 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.maps;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.util.AttributeSet;
import com.google.android.gms.R;
import org.microg.gms.maps.data.SharedTileCache;
import org.microg.gms.maps.markup.ClearableVectorLayer;
import org.oscim.android.MapView;
import org.oscim.android.canvas.AndroidBitmap;
import org.oscim.layers.marker.ItemizedLayer;
import org.oscim.layers.marker.MarkerItem;
import org.oscim.layers.marker.MarkerSymbol;
import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.layers.tile.vector.VectorTileLayer;
import org.oscim.layers.tile.vector.labeling.LabelLayer;
import org.oscim.map.Layers;
import org.oscim.theme.VtmThemes;
import org.oscim.tiling.ITileCache;
import org.oscim.tiling.source.oscimap4.OSciMap4TileSource;
public class BackendMapView extends MapView {
private static final String TAG = BackendMapView.class.getSimpleName();
private LabelLayer labels;
private BuildingLayer buildings;
private ItemizedLayer<MarkerItem> items;
private ClearableVectorLayer drawables;
@Override
public void onResume() {
super.onResume();
}
@Override
public void onPause() {
super.onPause();
}
public BackendMapView(Context context) {
super(context);
initialize();
}
public BackendMapView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
initialize();
}
ItemizedLayer<MarkerItem> items() {
return items;
}
BuildingLayer buildings() {
return buildings;
}
ClearableVectorLayer drawables() {
return drawables;
}
private void initialize() {
ITileCache cache = new SharedTileCache(getContext());
cache.setCacheSize(512 * (1 << 10));
OSciMap4TileSource tileSource = new OSciMap4TileSource();
tileSource.setCache(cache);
VectorTileLayer baseLayer = map().setBaseMap(tileSource);
Layers layers = map().layers();
layers.add(labels = new LabelLayer(map(), baseLayer));
layers.add(drawables = new ClearableVectorLayer(map()));
layers.add(buildings = new BuildingLayer(map(), baseLayer));
layers.add(items = new ItemizedLayer<MarkerItem>(map(), new MarkerSymbol(
new AndroidBitmap(BitmapFactory.decodeResource(getContext().getResources(), R.drawable.nop)), 0.5F, 1)));
map().setTheme(VtmThemes.DEFAULT);
}
}

View File

@ -33,9 +33,6 @@ import org.oscim.map.Map;
import java.util.ArrayList;
import java.util.List;
/**
* TODO
*/
public class PolylineImpl extends IPolylineDelegate.Stub implements DrawableMarkup {
private static final String TAG = "GmsMapsPolylineImpl";

View File

@ -34,6 +34,7 @@ import com.google.android.gms.people.internal.IPeopleService;
import com.google.android.gms.people.model.AccountMetadata;
import org.microg.gms.common.NonCancelToken;
import org.microg.gms.common.PackageUtils;
import java.io.File;
@ -48,6 +49,7 @@ public class PeopleServiceImpl extends IPeopleService.Stub {
@Override
public void loadOwners(final IPeopleCallbacks callbacks, boolean var2, boolean var3, final String accountName, String var5, int sortOrder) {
Log.d(TAG, "loadOwners: " + var2 + ", " + var3 + ", " + accountName + ", " + var5 + ", " + sortOrder);
PackageUtils.assertExtendedAccess(context);
AccountManager accountManager = AccountManager.get(context);
Bundle accountMetadata = new Bundle();
String accountType = context.getString(R.string.google_account_type);
@ -85,6 +87,7 @@ public class PeopleServiceImpl extends IPeopleService.Stub {
@Override
public void loadCircles(IPeopleCallbacks callbacks, String account, String pageGaiaId, String circleId, int type, String var6, boolean var7) throws RemoteException {
Log.d(TAG, "loadCircles: " + account + ", " + pageGaiaId + ", " + circleId + ", " + type + ", " + var6 + ", " + var7);
PackageUtils.assertExtendedAccess(context);
try {
DatabaseHelper databaseHelper = new DatabaseHelper(context);
Cursor owner = databaseHelper.getOwner(account);
@ -111,6 +114,7 @@ public class PeopleServiceImpl extends IPeopleService.Stub {
@Override
public ICancelToken loadOwnerAvatar(final IPeopleCallbacks callbacks, final String account, String pageId, int size, int flags) {
Log.d(TAG, "loadOwnerAvatar: " + account + ", " + pageId + ", " + size + ", " + flags);
PackageUtils.assertExtendedAccess(context);
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {

View File

@ -17,37 +17,52 @@
package org.microg.gms.ui;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import com.google.android.gms.R;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.places.internal.PlaceImpl;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
public class PlacePickerActivity extends AppCompatActivity {
import org.microg.gms.location.LocationConstants;
import org.microg.gms.maps.BackendMapView;
import org.microg.gms.maps.GmsMapsTypeHelper;
import org.microg.safeparcel.SafeParcelUtil;
import org.oscim.core.MapPosition;
import org.oscim.event.Event;
import org.oscim.map.Map;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class PlacePickerActivity extends AppCompatActivity implements Map.UpdateListener {
private static final String TAG = "GmsPlacePicker";
private static final String EXTRA_PRIMARY_COLOR = "primary_color";
private static final String EXTRA_PRIMARY_COLOR_DARK = "primary_color_dark";
private static final String EXTRA_CLIENT_VERSION = "gmscore_client_jar_version";
private static final String EXTRA_BOUNDS = "latlng_bounds";
private static final String EXTRA_ATTRIBUTION = "third_party_attributions";
private static final String EXTRA_FINAL_BOUNDS = "final_latlng_bounds";
private static final String EXTRA_PLACE = "selected_place";
private static final String EXTRA_STATUS = "status";
private int resultCode;
private PlaceImpl place;
private BackendMapView mapView;
private Intent resultIntent;
private AtomicBoolean geocoderInProgress = new AtomicBoolean(false);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
resultCode = RESULT_CANCELED;
resultIntent = new Intent();
if (getIntent().hasExtra(EXTRA_BOUNDS))
resultIntent.putExtra(EXTRA_FINAL_BOUNDS, getIntent().getParcelableExtra(EXTRA_BOUNDS));
place = new PlaceImpl();
setContentView(R.layout.pick_place);
@ -55,9 +70,58 @@ public class PlacePickerActivity extends AppCompatActivity {
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setBackgroundColor(getIntent().getIntExtra(EXTRA_PRIMARY_COLOR, 0));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
getWindow().setStatusBarColor(getIntent().getIntExtra(EXTRA_PRIMARY_COLOR_DARK, 0));
if (getIntent().hasExtra(LocationConstants.EXTRA_PRIMARY_COLOR)) {
toolbar.setBackgroundColor(getIntent().getIntExtra(LocationConstants.EXTRA_PRIMARY_COLOR, 0));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
getWindow().setStatusBarColor(getIntent().getIntExtra(LocationConstants.EXTRA_PRIMARY_COLOR_DARK, 0));
((TextView) findViewById(R.id.place_picker_title)).setTextColor(getIntent().getIntExtra(LocationConstants.EXTRA_PRIMARY_COLOR_DARK, 0));
}
mapView = (BackendMapView) findViewById(R.id.map);
mapView.map().getEventLayer().enableRotation(false);
mapView.map().getEventLayer().enableTilt(false);
mapView.map().events.bind(this);
LatLngBounds latLngBounds = getIntent().getParcelableExtra(LocationConstants.EXTRA_BOUNDS);
if (latLngBounds != null) {
place.viewport = latLngBounds;
mapView.map().getMapPosition().setByBoundingBox(GmsMapsTypeHelper.fromLatLngBounds(latLngBounds),
mapView.map().getWidth(), mapView.map().getHeight());
}
findViewById(R.id.place_picker_select).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
resultIntent.putExtra(LocationConstants.EXTRA_STATUS, SafeParcelUtil.asByteArray(new Status(CommonStatusCodes.SUCCESS)));
resultIntent.putExtra(LocationConstants.EXTRA_PLACE, SafeParcelUtil.asByteArray(place));
resultIntent.putExtra(LocationConstants.EXTRA_FINAL_BOUNDS, SafeParcelUtil.asByteArray(place.viewport));
setResult(RESULT_OK, resultIntent);
finish();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.pick_place, menu);
SearchView searchView = (SearchView) menu.findItem(R.id.menu_action_search).getActionView();
// TODO: search
return true;
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
mapView.onPause();
super.onPause();
}
@Override
@ -72,6 +136,57 @@ public class PlacePickerActivity extends AppCompatActivity {
@Override
protected void onDestroy() {
super.onDestroy();
setResult(resultCode, resultIntent);
}
@Override
public void onMapEvent(Event event, MapPosition position) {
place.viewport = GmsMapsTypeHelper.toLatLngBounds(mapView.map().viewport().getBBox(null, 0));
resultIntent.putExtra(LocationConstants.EXTRA_FINAL_BOUNDS, place.viewport);
place.latLng = GmsMapsTypeHelper.toLatLng(position.getGeoPoint());
place.name = getString(R.string.place_picker_location_lat_lng, place.latLng.latitude, place.latLng.longitude);
place.address = null;
updateInfoText();
if (geocoderInProgress.compareAndSet(false, true)) {
new Thread(new Runnable() {
@Override
public void run() {
try {
LatLng ll = null;
while (ll != place.latLng) {
ll = place.latLng;
Thread.sleep(1000);
}
Geocoder geocoder = new Geocoder(PlacePickerActivity.this);
List<Address> addresses = geocoder.getFromLocation(place.latLng.latitude, place.latLng.longitude, 1);
if (addresses != null && !addresses.isEmpty() && addresses.get(0).getMaxAddressLineIndex() > 0) {
Address address = addresses.get(0);
StringBuilder sb = new StringBuilder(address.getAddressLine(0));
for (int i = 1; i < address.getMaxAddressLineIndex(); ++i) {
sb.append(", ").append(address.getAddressLine(i));
}
if (place.latLng == ll) {
place.address = sb.toString();
place.name = address.getFeatureName();
if (TextUtils.isEmpty(place.name)) place.name = place.address;
runOnUiThread(new Runnable() {
@Override
public void run() {
updateInfoText();
}
});
}
}
} catch (Exception ignored) {
Log.w(TAG, ignored);
} finally {
geocoderInProgress.lazySet(false);
}
}
}).start();
}
}
private void updateInfoText() {
((TextView) findViewById(R.id.place_picker_info)).setText(place.name);
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2013-2015 microG Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.microg.gms.ui;
import org.microg.tools.selfcheck.AbstractSelfCheckActivity;
import org.microg.tools.selfcheck.InstalledPackagesChecks;
import org.microg.tools.selfcheck.RomSpoofSignatureChecks;
import org.microg.tools.selfcheck.SelfCheckGroup;
import java.util.List;
public class SelfCheckActivity extends AbstractSelfCheckActivity implements SelfCheckGroup.ResultCollector {
protected void prepareSelfCheckList(List<SelfCheckGroup> checks) {
checks.add(new RomSpoofSignatureChecks());
checks.add(new InstalledPackagesChecks());
}
}

View File

@ -17,13 +17,30 @@
package org.microg.gms.ui;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.preference.Preference;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.preference.PreferenceFragment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import com.google.android.gms.R;
import org.microg.tools.selfcheck.InstalledPackagesChecks;
import org.microg.tools.selfcheck.NlpOsCompatChecks;
import org.microg.tools.selfcheck.NlpStatusChecks;
import org.microg.tools.selfcheck.PermissionChecks;
import org.microg.tools.selfcheck.RomSpoofSignatureChecks;
import org.microg.tools.selfcheck.SelfCheckGroup;
import org.microg.tools.ui.AbstractAboutFragment;
import org.microg.tools.ui.AbstractSelfCheckFragment;
import java.util.List;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
public class SettingsActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -31,7 +48,8 @@ public class SettingsActivity extends AppCompatActivity {
setContentView(R.layout.settings_activity);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_wrapper, new MyPreferenceFragment()).commit();
.replace(R.id.content_wrapper, new MyPreferenceFragment())
.commit();
}
public static class MyPreferenceFragment extends PreferenceFragment {
@ -40,6 +58,64 @@ public class SettingsActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.gms_preferences);
findPreference(getString(R.string.self_check_title))
.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
getFragmentManager().beginTransaction()
.addToBackStack("root")
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(R.id.content_wrapper, new MySelfCheckFragment())
.commit();
return true;
}
});
findPreference(getString(R.string.pref_about_title))
.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
getFragmentManager().beginTransaction()
.addToBackStack("root")
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(R.id.content_wrapper, new MyAboutFragment())
.commit();
return true;
}
});
}
}
public static class MySelfCheckFragment extends AbstractSelfCheckFragment {
@Override
protected void prepareSelfCheckList(List<SelfCheckGroup> checks) {
checks.add(new RomSpoofSignatureChecks());
checks.add(new InstalledPackagesChecks());
if (SDK_INT > LOLLIPOP_MR1) {
checks.add(new PermissionChecks());
}
checks.add(new NlpOsCompatChecks());
checks.add(new NlpStatusChecks());
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
reset(LayoutInflater.from(getContext()));
}
}
public static class MyAboutFragment extends AbstractAboutFragment {
@Override
protected void collectLibraries(List<Library> libraries) {
libraries.add(new Library("org.microg.gms.api", "microG GmsApi", "Apache License 2.0, Copyright © microG Team"));
libraries.add(new Library("org.microg.safeparcel", "microG SafeParcel", "Apache License 2.0, Copyright © microG Team"));
libraries.add(new Library("org.microg.nlp", "microG UnifiedNlp", "Apache License 2.0, Copyright © microG Team"));
libraries.add(new Library("org.microg.nlp.api", "microG UnifiedNlp Api", "Apache License 2.0, Copyright © microG Team"));
libraries.add(new Library("de.hdodenhof.circleimageview", "CircleImageView", "Apache License 2.0, Copyright © Henning Dodenhof"));
libraries.add(new Library("org.oscim.android", "<vector<tile>>map", "GNU LGPLv3, Copyright © Hannes Janetzek"));
libraries.add(new Library("com.squareup.wire", "Wire Protocol Buffers", "Apache License 2.0, Copyright © Square Inc."));
}
}
}

View File

@ -23,20 +23,22 @@ import com.google.android.gms.R;
import org.microg.gms.common.Constants;
import org.microg.gms.common.PackageUtils;
import org.microg.tools.selfcheck.SelfCheckGroup;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;
public class InstalledPackagesChecks implements SelfCheckGroup {
@Override
public String getGroupName(Context context) {
return "Installed packages";
return context.getString(R.string.self_check_cat_gms_packages);
}
@Override
public void doChecks(Context context, ResultCollector collector) {
addPackageInstalledAndSignedResult(context, collector, "Play Services (GmsCore)", Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1);
addPackageInstalledAndSignedResult(context, collector, "Play Store (Phonesky)", "com.android.vending", Constants.GMS_PACKAGE_SIGNATURE_SHA1);
addPackageInstalledResult(context, collector, "Services Framework (GSF)", "com.google.android.gsf");
addPackageInstalledAndSignedResult(context, collector, context.getString(R.string.self_check_pkg_gms), Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1);
addPackageInstalledAndSignedResult(context, collector, context.getString(R.string.self_check_pkg_vending), "com.android.vending", Constants.GMS_PACKAGE_SIGNATURE_SHA1);
addPackageInstalledResult(context, collector, context.getString(R.string.self_check_pkg_gsf), Constants.GSF_PACKAGE_NAME);
}
private void addPackageInstalledAndSignedResult(Context context, ResultCollector collector, String nicePackageName, String androidPackageName, String signatureHash) {
@ -47,7 +49,7 @@ public class InstalledPackagesChecks implements SelfCheckGroup {
private boolean addPackageSignedResult(Context context, ResultCollector collector, String nicePackageName, String androidPackageName, String signatureHash) {
boolean hashMatches = signatureHash.equals(PackageUtils.firstSignatureDigest(context, androidPackageName));
collector.addResult(context.getString(R.string.self_check_name_correct_sig, nicePackageName), hashMatches,
collector.addResult(context.getString(R.string.self_check_name_correct_sig, nicePackageName), hashMatches ? Positive : Negative,
context.getString(R.string.self_check_resolution_correct_sig, nicePackageName));
return hashMatches;
}
@ -59,7 +61,7 @@ public class InstalledPackagesChecks implements SelfCheckGroup {
} catch (PackageManager.NameNotFoundException e) {
packageExists = false;
}
collector.addResult(context.getString(R.string.self_check_name_app_installed, nicePackageName), packageExists,
collector.addResult(context.getString(R.string.self_check_name_app_installed, nicePackageName), packageExists ? Positive : Negative,
context.getString(R.string.self_check_resolution_app_installed, nicePackageName));
return packageExists;
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2013-2016 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.tools.selfcheck;
import android.Manifest;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.util.Log;
import com.google.android.gms.R;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;
@TargetApi(Build.VERSION_CODES.M)
public class PermissionChecks implements SelfCheckGroup {
private static final String TAG = "SelfCheckPerms";
@Override
public String getGroupName(Context context) {
return context.getString(R.string.self_check_cat_permissions);
}
@Override
public void doChecks(Context context, ResultCollector collector) {
doPermissionCheck(context, collector, Manifest.permission.ACCESS_COARSE_LOCATION);
doPermissionCheck(context, collector, Manifest.permission.ACCESS_FINE_LOCATION);
doPermissionCheck(context, collector, Manifest.permission.WRITE_EXTERNAL_STORAGE);
doPermissionCheck(context, collector, Manifest.permission.GET_ACCOUNTS);
doPermissionCheck(context, collector, Manifest.permission.READ_PHONE_STATE);
doPermissionCheck(context, collector, com.google.android.gms.Manifest.permission.SEND);
}
private void doPermissionCheck(Context context, ResultCollector collector, final String permission) {
PackageManager pm = context.getPackageManager();
try {
PermissionInfo info = pm.getPermissionInfo(permission, 0);
PermissionGroupInfo groupInfo = info.group != null ? pm.getPermissionGroupInfo(info.group, 0) : null;
CharSequence permLabel = info.loadLabel(pm);
CharSequence groupLabel = groupInfo != null ? groupInfo.loadLabel(pm) : permLabel;
collector.addResult(context.getString(R.string.self_check_name_permission, permLabel),
context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED ? Positive : Negative,
context.getString(R.string.self_check_resolution_permission, groupLabel),
new SelfCheckGroup.CheckResolver() {
@Override
public void tryResolve(Fragment fragment) {
fragment.requestPermissions(new String[]{permission}, 0);
}
});
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, e);
}
}
}

View File

@ -18,12 +18,19 @@ package org.microg.tools.selfcheck;
import android.content.Context;
import android.content.pm.PackageManager;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import com.google.android.gms.R;
import org.microg.gms.common.Constants;
import org.microg.gms.common.PackageUtils;
import org.microg.tools.selfcheck.SelfCheckGroup;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static org.microg.gms.common.Constants.GMS_PACKAGE_SIGNATURE_SHA1;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Unknown;
public class RomSpoofSignatureChecks implements SelfCheckGroup {
@ -31,16 +38,16 @@ public class RomSpoofSignatureChecks implements SelfCheckGroup {
@Override
public String getGroupName(Context context) {
return "ROM spoof signature support";
return context.getString(R.string.self_check_cat_fake_sig);
}
@Override
public void doChecks(Context context, ResultCollector collector) {
if (addRomKnowsFakeSignaturePermission(context, collector)) {
if (addSystemGrantsFakeSignaturePermission(context, collector)) {
addSystemSpoofsSignature(context, collector);
}
boolean hasPermission = addRomKnowsFakeSignaturePermission(context, collector);
if (hasPermission) {
addSystemGrantsFakeSignaturePermission(context, collector);
}
addSystemSpoofsSignature(context, collector);
}
private boolean addRomKnowsFakeSignaturePermission(Context context, ResultCollector collector) {
@ -50,21 +57,26 @@ public class RomSpoofSignatureChecks implements SelfCheckGroup {
} catch (PackageManager.NameNotFoundException e) {
knowsPermission = false;
}
collector.addResult(context.getString(R.string.self_check_name_fake_sig_perm), knowsPermission,
collector.addResult(context.getString(R.string.self_check_name_fake_sig_perm), knowsPermission ? Positive : Unknown,
context.getString(R.string.self_check_resolution_fake_sig_perm));
return knowsPermission;
}
private boolean addSystemGrantsFakeSignaturePermission(Context context, ResultCollector collector) {
boolean grantsPermission = context.checkCallingOrSelfPermission(FAKE_SIGNATURE_PERMISSION) == PackageManager.PERMISSION_GRANTED;
collector.addResult(context.getString(R.string.self_check_name_perm_granted), grantsPermission,
context.getString(R.string.self_check_resolution_perm_granted));
boolean grantsPermission = ContextCompat.checkSelfPermission(context, FAKE_SIGNATURE_PERMISSION) == PERMISSION_GRANTED;
collector.addResult(context.getString(R.string.self_check_name_perm_granted), grantsPermission ? Positive : Negative,
context.getString(R.string.self_check_resolution_perm_granted), new CheckResolver() {
@Override
public void tryResolve(Fragment fragment) {
fragment.requestPermissions(new String[]{FAKE_SIGNATURE_PERMISSION}, 0);
}
});
return grantsPermission;
}
private boolean addSystemSpoofsSignature(Context context, ResultCollector collector) {
boolean spoofsSignature = Constants.GMS_PACKAGE_SIGNATURE_SHA1.equals(PackageUtils.firstSignatureDigest(context, Constants.GMS_PACKAGE_NAME));
collector.addResult(context.getString(R.string.self_check_name_system_spoofs), spoofsSignature,
boolean spoofsSignature = GMS_PACKAGE_SIGNATURE_SHA1.equals(PackageUtils.firstSignatureDigest(context, Constants.GMS_PACKAGE_NAME));
collector.addResult(context.getString(R.string.self_check_name_system_spoofs), spoofsSignature ? Positive : Negative,
context.getString(R.string.self_check_resolution_system_spoofs));
return spoofsSignature;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -22,11 +22,112 @@
<include layout="@layout/toolbar"/>
<TextView
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="@string/pick_place_desc"/>
android:layout_height="0dip"
android:layout_weight="1">
<org.microg.gms.maps.BackendMapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:paddingBottom="41dip"
android:src="@drawable/maps_default_marker"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/place_picker_select"
android:layout_width="fill_parent"
android:layout_height="72dp"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:orientation="horizontal">
<ImageView
android:id="@+id/place_picker_icon"
android:layout_width="32.0dip"
android:layout_height="72dp"
android:layout_gravity="top"
android:layout_marginEnd="16.0dip"
android:layout_marginLeft="16.0dip"
android:layout_marginRight="16.0dip"
android:layout_marginStart="16.0dip"
android:src="@drawable/ic_map_marker"/>
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="@+id/place_picker_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginTop="12.0dip"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/place_picker_select_title"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="?attr/colorAccent"/>
<TextView
android:id="@+id/place_picker_info"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginTop="36.0dip"
android:ellipsize="end"
android:lines="1"
android:text="(0.0000000, 0.0000000)"
android:textAppearance="?android:textAppearanceSmall"/>
</FrameLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="#7f7f7f7f"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#fff1f1f1"
android:focusable="false"
android:orientation="vertical"
android:paddingLeft="8.0dip"
android:paddingRight="8.0dip">
<TextView
android:id="@id/title"
android:layout_width="fill_parent"
android:layout_height="40.0dip"
android:gravity="center_vertical"
android:paddingLeft="8.0dip"
android:text="@string/place_picker_nearby_places"
android:textAllCaps="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="#ff7f7f7f"
android:textStyle="bold"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
<TextView
android:id="@+id/hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16.0dip"
android:text="Can't load nearby places."
android:textAppearance="?android:textAppearanceLarge"
android:textColor="#ff7f7f7f"/>
</RelativeLayout>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2013-2016 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_action_search"
android:icon="@drawable/ic_magnify"
android:title="@android:string/search_go"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView"/>
</menu>

View File

@ -46,10 +46,6 @@
<string name="pref_auth_trust_google_title">Поуздај се у Гугл за дозволе апликација</string>
<string name="pref_auth_trust_google_summary">Ако је искључено корисник ће бити упитан пре него се захтев за овлашћењем апликација пошаље Гуглу. Неке апликације неће моћи да користе Гуглов налог ако је ово искључено.</string>
<string name="prefcat_setup">Поставка</string>
<string name="self_check_title">микроГ самопровера</string>
<string name="self_check_desc">Провера исправности подешавања система за коришћење микроГ услуга.</string>
<string name="self_check_name_fake_sig_perm">Систем има подршку заваравања потписа: </string>
<string name="self_check_resolution_fake_sig_perm">Ваш РОМ нема уграђену подршку за заваравање потписа. Ипак можете да користите Xposed или друге начине заваравања потписа. Погледајте документацију да видите који РОМови подржавају заваравање потписа и како да користите микроГ на РОМовима који не подржавају.</string>
<string name="self_check_name_perm_granted">Систем одобрава дозволу заваравања потписа: </string>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2013-2016 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.
-->
<resources>
<bool name="is_gmscore">true</bool>
</resources>

View File

@ -49,21 +49,6 @@ This can take a couple of minutes."</string>
<string name="pref_auth_trust_google_title">Trust Google for app permissions</string>
<string name="pref_auth_trust_google_summary">When disabled, the user is asked before an apps authorization request is sent to Google. Some applications will fail to use the Google account if this is disabled.</string>
<string name="prefcat_setup">Setup</string>
<string name="self_check_title">microG Self-Check</string>
<string name="self_check_desc">Check if the system is correctly set up to use microG.</string>
<string name="self_check_name_fake_sig_perm">System has signature spoofing support: </string>
<string name="self_check_resolution_fake_sig_perm">You ROM has no native support for signature spoofing. You can still use Xposed or other systems to spoof signature. Please check the documentation on which ROMs do support signature spoofing and how to use microG on ROMs that do not.</string>
<string name="self_check_name_perm_granted">System grants signature spoofing permission: </string>
<string name="self_check_resolution_perm_granted">This is a strong indicator that the ROM does support signature spoofing, but requires further action to activate it. Please check the documentation on which steps might be required.</string>
<string name="self_check_name_system_spoofs">System spoofs signature: </string>
<string name="self_check_resolution_system_spoofs">This is a strong indicator that the ROM does support signature spoofing, but requires further action to activate it. Please check the documentation on which steps might be required.</string>
<string name="self_check_name_app_installed">%1$s installed: </string>
<string name="self_check_resolution_app_installed">Install the application %1$s or a compatible one. Please check the documentation on which applications are compatible.</string>
<string name="self_check_name_correct_sig">%1$s has correct signature: </string>
<string name="self_check_resolution_correct_sig">Either the installed %1$s is not compatible, signature spoofing is not enabled for it or your ROM does not properly support signature spoofing. Please check the documentation on which applications and ROMs are compatible.</string>
<string name="prefcat_services">Background services</string>
<string name="pref_checkin_enable" translatable="false">checkin_enable_service</string>
@ -87,4 +72,41 @@ This can take a couple of minutes."</string>
<string name="pick_place_title">Pick a place</string>
<string name="pick_place_desc">Place picker is not yet available.</string>
<string name="prefcat_about">About</string>
<string name="pref_about_title">About microG Services Core</string>
<string name="pref_about_summary">Version information and used libraries</string>
<string name="self_check_cat_fake_sig">Signature spoofing support</string>
<string name="self_check_name_fake_sig_perm">System has signature spoofing support: </string>
<string name="self_check_resolution_fake_sig_perm">Your ROM has no native support for signature spoofing. You can still use Xposed or other systems to spoof signature. Please check the documentation on which ROMs do support signature spoofing and how to use microG on ROMs that do not.</string>
<string name="self_check_name_perm_granted">System grants signature spoofing permission: </string>
<string name="self_check_resolution_perm_granted">This is a strong indicator that the ROM does support signature spoofing, but requires further action to activate it. Please check the documentation on which steps might be required.</string>
<string name="self_check_name_system_spoofs">System spoofs signature: </string>
<string name="self_check_resolution_system_spoofs">Please check the documentation on which steps might be required.</string>
<string name="self_check_cat_gms_packages">Installed packages</string>
<string name="self_check_pkg_gms">Play Services (GmsCore)</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">%1$s installed: </string>
<string name="self_check_resolution_app_installed">Install the application %1$s or a compatible one. Please check the documentation on which applications are compatible.</string>
<string name="self_check_name_correct_sig">%1$s has correct signature: </string>
<string name="self_check_resolution_correct_sig">Either the installed %1$s is not compatible or signature spoofing is not active for it. Please check the documentation on which applications and ROMs are compatible.</string>
<string name="perm_extended_access_label">Extended access to Google services</string>
<string name="self_check_cat_permissions">Permissions granted</string>
<string name="self_check_name_permission">Permission to %1$s:</string>
<string name="self_check_resolution_permission">Touch here to grant permission to %1$s. Not granting the permission can result in misbehaving applications.</string>
<string name="self_check_perm_location">location</string>
<string name="self_check_perm_storage">storage</string>
<string name="self_check_perm_contacts">contacts</string>
<string name="self_check_perm_phone">phone</string>
<string name="lacking_permission_toast">microG Services Core: Lacking permission %1$s</string>
<string name="place_picker_select_title">Select this location</string>
<string name="place_picker_nearby_places">Nearby places</string>
<string name="place_picker_location_lat_lng">(%1$.7f, %2$.7f)</string>
</resources>

View File

@ -17,11 +17,9 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/prefcat_setup">
<Preference
android:key="@string/self_check_title"
android:summary="@string/self_check_desc"
android:title="@string/self_check_title">
<intent
android:targetClass="org.microg.gms.ui.SelfCheckActivity"
android:targetPackage="com.google.android.gms"/>
</Preference>
</PreferenceCategory>
<PreferenceCategory android:title="@string/prefcat_services">
@ -50,4 +48,10 @@
android:targetPackage="com.google.android.gms"/>
</Preference>
</PreferenceCategory>
<PreferenceCategory android:title="@string/prefcat_about">
<Preference
android:key="@string/pref_about_title"
android:summary="@string/pref_about_summary"
android:title="@string/pref_about_title"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@ -8,3 +8,5 @@ include ':unifiednlp-compat'
include ':play-services-api'
include ':play-services-core'
include ':microg-ui-tools'