From 36858799024f68108cfa6a6093ccc60d2ad0d529 Mon Sep 17 00:00:00 2001 From: mar-v-in Date: Fri, 22 Aug 2014 22:08:44 +0200 Subject: [PATCH] Update - Add support for ProviderInstaller (fake) - Add support for Auth (insecure) - Update to latest version of osmdroid --- AndroidManifest.xml | 15 +++- proguard.flags | 5 ++ .../android/auth/IAuthManagerService.aidl | 6 ++ src/com/google/android/gms/auth/GetToken.java | 31 +++++++ .../android/gms/auth/TokenActivity.java | 56 ++++++++++++ .../security/ProviderInstallerImpl.java | 26 ++++++ .../gms/auth/AuthManagerServiceImpl.java | 90 +++++++++++++++++++ src/org/microg/gms/maps/GoogleMapImpl.java | 55 +++++++++--- .../gms/maps/bitmap/BitmapDescriptor.java | 8 +- .../maps/camera/CameraUpdateFactoryImpl.java | 2 +- .../microg/gms/maps/markup/InfoWindow.java | 12 ++- .../microg/gms/maps/markup/MarkerImpl.java | 49 +++++----- .../microg/tools/AccountPickerActivity.java | 52 +++++++++++ 13 files changed, 370 insertions(+), 37 deletions(-) create mode 100644 src/com/google/android/auth/IAuthManagerService.aidl create mode 100644 src/com/google/android/gms/auth/GetToken.java create mode 100644 src/com/google/android/gms/auth/TokenActivity.java create mode 100644 src/com/google/android/gms/common/security/ProviderInstallerImpl.java create mode 100644 src/org/microg/gms/auth/AuthManagerServiceImpl.java create mode 100644 src/org/microg/tools/AccountPickerActivity.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 3be7e68c..029c566e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -17,7 +17,7 @@ + android:versionCode="5089036"> @@ -27,6 +27,8 @@ + + @@ -116,5 +118,16 @@ + + + + + + + + + + diff --git a/proguard.flags b/proguard.flags index 84d998cc..e53c0c85 100644 --- a/proguard.flags +++ b/proguard.flags @@ -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 *; +} \ No newline at end of file diff --git a/src/com/google/android/auth/IAuthManagerService.aidl b/src/com/google/android/auth/IAuthManagerService.aidl new file mode 100644 index 00000000..3cb2ce81 --- /dev/null +++ b/src/com/google/android/auth/IAuthManagerService.aidl @@ -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); +} diff --git a/src/com/google/android/gms/auth/GetToken.java b/src/com/google/android/gms/auth/GetToken.java new file mode 100644 index 00000000..0095d0bb --- /dev/null +++ b/src/com/google/android/gms/auth/GetToken.java @@ -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); + } +} diff --git a/src/com/google/android/gms/auth/TokenActivity.java b/src/com/google/android/gms/auth/TokenActivity.java new file mode 100644 index 00000000..5b89b78d --- /dev/null +++ b/src/com/google/android/gms/auth/TokenActivity.java @@ -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() { + @Override + public void run(AccountManagerFuture 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())); + } +} diff --git a/src/com/google/android/gms/common/security/ProviderInstallerImpl.java b/src/com/google/android/gms/common/security/ProviderInstallerImpl.java new file mode 100644 index 00000000..b23c2277 --- /dev/null +++ b/src/com/google/android/gms/common/security/ProviderInstallerImpl.java @@ -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..."); + } +} diff --git a/src/org/microg/gms/auth/AuthManagerServiceImpl.java b/src/org/microg/gms/auth/AuthManagerServiceImpl.java new file mode 100644 index 00000000..fe5cc9de --- /dev/null +++ b/src/org/microg/gms/auth/AuthManagerServiceImpl.java @@ -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 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; + } +} diff --git a/src/org/microg/gms/maps/GoogleMapImpl.java b/src/org/microg/gms/maps/GoogleMapImpl.java index 5c981163..68dd6fca 100644 --- a/src/org/microg/gms/maps/GoogleMapImpl.java +++ b/src/org/microg/gms/maps/GoogleMapImpl.java @@ -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 diff --git a/src/org/microg/gms/maps/bitmap/BitmapDescriptor.java b/src/org/microg/gms/maps/bitmap/BitmapDescriptor.java index a56cd623..661455d3 100644 --- a/src/org/microg/gms/maps/bitmap/BitmapDescriptor.java +++ b/src/org/microg/gms/maps/bitmap/BitmapDescriptor.java @@ -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(); } diff --git a/src/org/microg/gms/maps/camera/CameraUpdateFactoryImpl.java b/src/org/microg/gms/maps/camera/CameraUpdateFactoryImpl.java index b63660e5..33b57073 100644 --- a/src/org/microg/gms/maps/camera/CameraUpdateFactoryImpl.java +++ b/src/org/microg/gms/maps/camera/CameraUpdateFactoryImpl.java @@ -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)); } }); } diff --git a/src/org/microg/gms/maps/markup/InfoWindow.java b/src/org/microg/gms/maps/markup/InfoWindow.java index 6b05206f..c7448065 100644 --- a/src/org/microg/gms/maps/markup/InfoWindow.java +++ b/src/org/microg/gms/maps/markup/InfoWindow.java @@ -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); diff --git a/src/org/microg/gms/maps/markup/MarkerImpl.java b/src/org/microg/gms/maps/markup/MarkerImpl.java index 9ceb28d2..0cffb1bf 100644 --- a/src/org/microg/gms/maps/markup/MarkerImpl.java +++ b/src/org/microg/gms/maps/markup/MarkerImpl.java @@ -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(new DefaultBitmapDescriptor(0))); - Log.d(TAG, "New: " + id + " with title " + title + " @ " + position); + Log.d(TAG, "New marker " + id + " with title " + title + " @ " + position); } @Override diff --git a/src/org/microg/tools/AccountPickerActivity.java b/src/org/microg/tools/AccountPickerActivity.java new file mode 100644 index 00000000..7aa62fd3 --- /dev/null +++ b/src/org/microg/tools/AccountPickerActivity.java @@ -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); + } + } +}