- Add support for ProviderInstaller (fake)
- Add support for Auth (insecure)
- Update to latest version of osmdroid
This commit is contained in:
mar-v-in 2014-08-22 22:08:44 +02:00
parent 001384735b
commit 3685879902
13 changed files with 370 additions and 37 deletions

View File

@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.gms"
android:versionCode="4452036">
android:versionCode="5089036">
<uses-sdk android:minSdkVersion="16" />
@ -27,6 +27,8 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FAKE_PACKAGE_SIGNATURE" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<application
android:label="@string/gms_app_name">
@ -116,5 +118,16 @@
<action android:name="com.google.android.location.internal.GoogleLocationManagerService.START" />
</intent-filter>
</service>
<activity android:name="org.microg.tools.AccountPickerActivity" android:exported="true"
android:excludeFromRecents="true" android:theme="@android:style/Theme.Holo.Dialog">
<intent-filter>
<action android:name="com.google.android.gms.common.account.CHOOSE_ACCOUNT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service android:name=".auth.GetToken" android:exported="true" />
<activity android:name=".auth.TokenActivity" android:exported="true" />
</application>
</manifest>

View File

@ -3,3 +3,8 @@
# Keep dynamically loaded GMS classes
-keep public class com.google.android.gms.maps.internal.CreatorImpl
-keep public class com.google.android.gms.common.security.ProviderInstallerImpl
-keepclassmembers class com.google.android.gms.common.security.ProviderInstallerImpl {
public *;
}

View File

@ -0,0 +1,6 @@
package com.google.android.auth;
interface IAuthManagerService {
Bundle getToken(String accountName, String scope, in Bundle extras);
Bundle clearToken(String token, in Bundle extras);
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2014 μg 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 com.google.android.gms.auth;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import org.microg.gms.auth.AuthManagerServiceImpl;
public class GetToken extends Service {
@Override
public IBinder onBind(Intent intent) {
return new AuthManagerServiceImpl(this);
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2014 μg 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 com.google.android.gms.auth;
import android.accounts.*;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import java.io.IOException;
public class TokenActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
extras.get("KEY");
Log.d("TokenActivity", extras.toString());
AccountManager accountManager = AccountManager.get(this);
accountManager.getAuthToken(new Account(extras.getString("authAccount"), "com.google"), extras.getString("service"), extras.getBundle("callerExtras"), this, new AccountManagerCallback<Bundle>() {
@Override
public void run(AccountManagerFuture<Bundle> future) {
try {
Bundle result = future.getResult();
if (result != null) {
result.get("KEY");
Log.d("TokenActivity", result.toString());
} else {
Log.d("TokenActivity", "null-result");
}
} catch (OperationCanceledException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (AuthenticatorException e) {
e.printStackTrace();
}
}
}, new Handler(getMainLooper()));
}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2014 μg 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 com.google.android.gms.common.security;
import android.content.Context;
import android.util.Log;
public class ProviderInstallerImpl {
public static void insertProvider(Context context) {
Log.d("ProviderInstallerImpl", "yep, i should do something with OpenSSL here...");
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2014 μg 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.auth;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import com.google.android.auth.IAuthManagerService;
public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
public static final String GOOGLE_ACCOUNT_TYPE = "com.google";
public static final String KEY_AUTHORITY = "authority";
public static final String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
public static final String KEY_CALLBACK_INTENT = "callback_intent";
public static final String KEY_CALLER_UID = "callerUid";
public static final String KEY_CLIENT_PACKAGE_NAME = "clientPackageName";
public static final String KEY_HANDLE_NOTIFICATION = "handle_notification";
public static final String KEY_REQUEST_ACTIONS = "request_visible_actions";
public static final String KEY_REQUEST_VISIBLE_ACTIVITIES = "request_visible_actions";
public static final String KEY_SUPPRESS_PROGRESS_SCREEN = "suppressProgressScreen";
public static final String KEY_SYNC_EXTRAS = "sync_extras";
public static final String KEY_AUTH_TOKEN = "authtoken";
public static final String KEY_ERROR = "Error";
public static final String KEY_USER_RECOVERY_INTENT = "userRecoveryIntent";
private Context context;
private class State {
String authToken;
}
public AuthManagerServiceImpl(Context context) {
this.context = context;
}
@Override
public Bundle getToken(String accountName, String scope, Bundle extras) throws RemoteException {
String packageName = extras.containsKey(KEY_ANDROID_PACKAGE_NAME) ? extras.getString(KEY_ANDROID_PACKAGE_NAME)
: extras.containsKey(KEY_CLIENT_PACKAGE_NAME) ? extras.getString(KEY_CLIENT_PACKAGE_NAME) : null;
boolean notify = extras.getBoolean(KEY_HANDLE_NOTIFICATION, false);
Log.d("AuthManagerService", "getToken: account:" + accountName + " scope:" + scope + " extras:" + extras);
AccountManagerFuture<Bundle> authToken = AccountManager.get(context).getAuthToken(new Account(accountName, GOOGLE_ACCOUNT_TYPE), scope, extras, notify, null, new Handler(Looper.getMainLooper()));
try {
Bundle requestResult = authToken.getResult();
if (!requestResult.containsKey(AccountManager.KEY_AUTHTOKEN) && requestResult.containsKey(AccountManager.KEY_INTENT)) {
Intent intent = requestResult.getParcelable(AccountManager.KEY_INTENT);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
Log.d("getToken", requestResult.toString());
Bundle result = new Bundle();
result.putString(KEY_AUTH_TOKEN, requestResult.getString(AccountManager.KEY_AUTHTOKEN));
result.putString(KEY_ERROR, "Unknown");
result.putParcelable(KEY_USER_RECOVERY_INTENT, requestResult.getParcelable(AccountManager.KEY_INTENT));
return result;
} catch (Exception e) {
Log.w("AuthManagerService", e);
throw new RemoteException(e.getMessage());
}
}
@Override
public Bundle clearToken(String token, Bundle extras) throws RemoteException {
return null;
}
}

View File

@ -16,10 +16,13 @@
package org.microg.gms.maps;
import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.LayoutInflater;
@ -230,6 +233,10 @@ public class GoogleMapImpl {
}
}
private void runLater(Runnable runnable) {
new Handler(Looper.getMainLooper()).post(runnable);
}
private class Delegate extends IGoogleMapDelegate.Stub {
@Override
public CameraPosition getCameraPosition() throws RemoteException {
@ -248,25 +255,53 @@ public class GoogleMapImpl {
}
@Override
public void moveCamera(IObjectWrapper cameraUpdate) throws RemoteException {
((CameraUpdate) ObjectWrapper.unwrap(cameraUpdate)).update(GoogleMapImpl.this);
public void moveCamera(final IObjectWrapper cameraUpdate) throws RemoteException {
runLater(new Runnable() {
@Override
public void run() {
((CameraUpdate) ObjectWrapper.unwrap(cameraUpdate)).update(GoogleMapImpl.this);
}
});
}
@Override
public void animateCamera(IObjectWrapper cameraUpdate) throws RemoteException {
((CameraUpdate) ObjectWrapper.unwrap(cameraUpdate)).update(GoogleMapImpl.this);
public void animateCamera(final IObjectWrapper cameraUpdate) throws RemoteException {
runLater(new Runnable() {
@Override
public void run() {
((CameraUpdate) ObjectWrapper.unwrap(cameraUpdate)).update(GoogleMapImpl.this);
}
});
}
@Override
public void animateCameraWithCallback(IObjectWrapper cameraUpdate, ICancelableCallback callback) throws RemoteException {
((CameraUpdate) ObjectWrapper.unwrap(cameraUpdate)).update(GoogleMapImpl.this);
if (callback != null) callback.onFinish();
public void animateCameraWithCallback(final IObjectWrapper cameraUpdate, final ICancelableCallback callback) throws RemoteException {
runLater(new Runnable() {
@Override
public void run() {
((CameraUpdate) ObjectWrapper.unwrap(cameraUpdate)).update(GoogleMapImpl.this);
if (callback != null) try {
callback.onFinish();
} catch (RemoteException e) {
Log.w(TAG, e);
}
}
});
}
@Override
public void animateCameraWithDurationAndCallback(IObjectWrapper cameraUpdate, int duration, ICancelableCallback callback) throws RemoteException {
((CameraUpdate) ObjectWrapper.unwrap(cameraUpdate)).update(GoogleMapImpl.this);
if (callback != null) callback.onFinish();
public void animateCameraWithDurationAndCallback(final IObjectWrapper cameraUpdate, int duration, final ICancelableCallback callback) throws RemoteException {
runLater(new Runnable() {
@Override
public void run() {
((CameraUpdate) ObjectWrapper.unwrap(cameraUpdate)).update(GoogleMapImpl.this);
if (callback != null) try {
callback.onFinish();
} catch (RemoteException e) {
Log.w(TAG, e);
}
}
});
}
@Override

View File

@ -18,11 +18,13 @@ package org.microg.gms.maps.bitmap;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.dynamic.ObjectWrapper;
public class BitmapDescriptor {
private final IObjectWrapper remoteObject;
private boolean loadStarted = false;
public BitmapDescriptor(IObjectWrapper remoteObject) {
this.remoteObject = remoteObject;
@ -56,14 +58,18 @@ public class BitmapDescriptor {
'}';
}
public void loadBitmapAsync(final Context context, final Runnable after) {
public synchronized void loadBitmapAsync(final Context context, final Runnable after) {
if (loadStarted) return;
loadStarted = true;
if (getDescriptor() != null) {
new Thread(new Runnable() {
@Override
public void run() {
Log.d("BitmapDescriptor", "Start loading " + getDescriptor());
if (getDescriptor().loadBitmap(context) != null) {
after.run();
}
Log.d("BitmapDescriptor", "Done loading " + getDescriptor());
}
}).start();
}

View File

@ -142,9 +142,9 @@ public class CameraUpdateFactoryImpl extends ICameraUpdateFactoryDelegate.Stub {
public void update(GoogleMapImpl map) {
double latSpan = bounds.northEast.latitude - bounds.southWest.latitude,
lonSpan = bounds.northEast.longitude - bounds.southWest.longitude;
map.getController().zoomToSpan((int) (latSpan * 1E6), (int) (lonSpan * 1E6));
map.getController().setCenter(new GeoPoint((int) ((bounds.southWest.latitude + latSpan/2) * 1E6),
(int) ((bounds.southWest.longitude + lonSpan/2) * 1E6)));
map.getController().zoomToSpan((int) (latSpan * 1E6), (int) (lonSpan * 1E6));
}
});
}

View File

@ -86,14 +86,20 @@ public class InfoWindow extends Overlay {
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
if (window != null && marker.getHeight() != -1) {
if (window != null && marker.getHeight() != -1 && !shadow) {
try {
Point zero = mapView.getProjection().toPixels(new GeoPoint(0, 0), null);
Log.d(TAG, "draw InfoWindow");
window.measure(0, 0);
window.layout(0, 0, window.getMeasuredWidth(), window.getMeasuredHeight());
Point point = mapView.getProjection().toPixels(marker.getPosition().toGeoPoint(), null);
/*
// osmdroid 4.1 bugfix
Point zero = mapView.getProjection().toPixels(new GeoPoint(0, 0), null);
point.offset(-zero.x, -zero.y);
*/
point.offset(-window.getMeasuredWidth() / 2, -window.getMeasuredHeight() - marker.getHeight());
Log.d(TAG, point.toString());
window.layout(0, 0, window.getMeasuredWidth(), window.getMeasuredHeight());
canvas.save();
canvas.translate(point.x, point.y);
window.draw(canvas);

View File

@ -17,6 +17,9 @@
package org.microg.gms.maps.markup;
import android.graphics.*;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.RemoteException;
import android.util.Log;
import com.google.android.gms.dynamic.IObjectWrapper;
@ -84,28 +87,32 @@ public class MarkerImpl extends IMarkerDelegate.Stub {
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
if (!shadow) {
Bitmap bitmap = icon.getBitmap();
if (bitmap != null) {
mapView.getProjection().toPixels(position.toGeoPoint(), point);
float x = point.x - bitmap.getWidth() * anchorU;
float y = point.y - bitmap.getHeight() * anchorV;
Paint paint = new Paint();
paint.setAlpha((int) (alpha * 255));
Matrix matrix = new Matrix();
matrix.setRotate(rotation, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
matrix.postTranslate(x, y);
canvas.drawBitmap(bitmap, matrix, paint);
} else {
icon.loadBitmapAsync(map.getContext(), new Runnable() {
@Override
public void run() {
map.redraw();
}
});
if (shadow /*&& flat*/) return; // shadows are broken right now, we skip them
Bitmap bitmap = icon.getBitmap();
if (bitmap != null) {
mapView.getProjection().toPixels(position.toGeoPoint(), point);
float x = point.x - bitmap.getWidth() * anchorU;
float y = point.y - bitmap.getHeight() * anchorV;
Paint paint = new Paint();
paint.setAlpha((int) (alpha * 255));
if (shadow) {
paint.setColorFilter(new PorterDuffColorFilter(Color.argb((int) (128 * alpha), 0, 0, 0), PorterDuff.Mode.SRC_IN));
}
Matrix matrix = new Matrix();
matrix.setRotate(rotation, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
if (shadow) {
matrix.postSkew(-0.9F, 0);
matrix.postScale(1, 0.5F);
}
matrix.postTranslate(x, y);
canvas.drawBitmap(bitmap, matrix, paint);
} else {
// TODO: shadow based on flat
icon.loadBitmapAsync(map.getContext(), new Runnable() {
@Override
public void run() {
map.redraw();
}
});
}
}
};
@ -126,7 +133,7 @@ public class MarkerImpl extends IMarkerDelegate.Stub {
this.icon = options.getIcon();
if (icon == null)
icon = new BitmapDescriptor(new ObjectWrapper<DefaultBitmapDescriptor>(new DefaultBitmapDescriptor(0)));
Log.d(TAG, "New: " + id + " with title " + title + " @ " + position);
Log.d(TAG, "New marker " + id + " with title " + title + " @ " + position);
}
@Override

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2014 μg 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;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
/**
* This is just an activity that forwards to the systems native account picker
*/
public class AccountPickerActivity extends Activity {
private static final int REQUEST_CODE = AccountPickerActivity.class.hashCode();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
Intent intent = new Intent();
ComponentName componentName =
ComponentName.unflattenFromString("android/.accounts.ChooseTypeAndAccountActivity");
intent.setClassName(componentName.getPackageName(), componentName.getClassName());
intent.putExtras(extras);
startActivityForResult(intent, REQUEST_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
setResult(resultCode, data);
finish();
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}