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);
+ }
+ }
+}