WIP: Location API

This commit is contained in:
mar-v-in 2015-01-15 20:11:31 +01:00
parent 8b42163800
commit d2fb7d569b
23 changed files with 1035 additions and 40 deletions

View File

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest package="com.google.android.gms"> <manifest xmlns:android="http://schemas.android.com/apk/res/android"
<uses-sdk minSdkVersion="5" /> package="com.google.android.gms">
<uses-sdk android:minSdkVersion="5" />
</manifest> </manifest>

View File

@ -0,0 +1,40 @@
package com.google.android.gms.common;
import android.os.Bundle;
@Deprecated
public interface GooglePlayServicesClient {
void connect();
void disconnect();
boolean isConnected();
boolean isConnecting();
void registerConnectionCallbacks(ConnectionCallbacks listener);
boolean isConnectionCallbacksRegistered(ConnectionCallbacks listener);
void unregisterConnectionCallbacks(ConnectionCallbacks listener);
void registerConnectionFailedListener(OnConnectionFailedListener listener);
boolean isConnectionFailedListenerRegistered(OnConnectionFailedListener listener);
void unregisterConnectionFailedListener(OnConnectionFailedListener listener);
@Deprecated
public interface OnConnectionFailedListener {
void onConnectionFailed(ConnectionResult result);
}
@Deprecated
public interface ConnectionCallbacks {
void onConnected(Bundle connectionHint);
void onDisconnected();
}
}

View File

@ -49,7 +49,8 @@ public class GooglePlayServicesUtil {
} }
public static int isGooglePlayServicesAvailable(Context context) { public static int isGooglePlayServicesAvailable(Context context) {
return 0; // TODO // As we can't know right now if the later desired feature is available, we just pretend it to be.
return ConnectionResult.SUCCESS;
} }
public static boolean isGoogleSignedUid(PackageManager packageManager, int uid) { public static boolean isGoogleSignedUid(PackageManager packageManager, int uid) {

View File

@ -1,5 +1,8 @@
package com.google.android.gms.common.api; package com.google.android.gms.common.api;
import android.content.Context;
import android.os.Looper;
/** /**
* Describes a section of the Google Play Services API that should be made available. Instances of * Describes a section of the Google Play Services API that should be made available. Instances of
* this should be passed into {@link GoogleApiClient.Builder#addApi(Api)} to enable the appropriate * this should be passed into {@link GoogleApiClient.Builder#addApi(Api)} to enable the appropriate
@ -13,6 +16,16 @@ package com.google.android.gms.common.api;
* See {@link GoogleApiClient.Builder} for usage examples. * See {@link GoogleApiClient.Builder} for usage examples.
*/ */
public final class Api<O extends Api.ApiOptions> { public final class Api<O extends Api.ApiOptions> {
private final Builder<O> builder;
public Api(Builder<O> builder) {
this.builder = builder;
}
public Builder<O> getBuilder() {
return builder;
}
/** /**
* Base interface for API options. These are used to configure specific parameters for * Base interface for API options. These are used to configure specific parameters for
@ -34,7 +47,7 @@ public final class Api<O extends Api.ApiOptions> {
/** /**
* {@link ApiOptions} implementation for {@link Api}s that do not take any options. * {@link ApiOptions} implementation for {@link Api}s that do not take any options.
*/ */
public class NoOptions implements NotRequiredOptions { public final class NoOptions implements NotRequiredOptions {
} }
/** /**
@ -43,4 +56,16 @@ public final class Api<O extends Api.ApiOptions> {
public interface Optional extends HasOptions, NotRequiredOptions { public interface Optional extends HasOptions, NotRequiredOptions {
} }
} }
public interface Connection {
public void connect();
public void disconnect();
public boolean isConnected();
}
public interface Builder<O extends ApiOptions> {
Connection build(Context context, Looper looper, O options, AccountInfo accountInfo,
GoogleApiClient.ConnectionCallbacks callbacks,
GoogleApiClient.OnConnectionFailedListener connectionFailedListener);
}
} }

View File

@ -3,12 +3,19 @@ package com.google.android.gms.common.api;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.view.View; import android.view.View;
import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.ConnectionResult;
import org.microg.gms.Constants;
import org.microg.gms.common.api.GoogleApiClientImpl;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Handler;
/** /**
* The main entry point for Google Play services integration. * The main entry point for Google Play services integration.
@ -209,13 +216,27 @@ public interface GoogleApiClient {
* Builder to configure a {@link GoogleApiClient}. * Builder to configure a {@link GoogleApiClient}.
*/ */
public class Builder { public class Builder {
private final Context context;
private final Map<Api, Api.ApiOptions> apis = new HashMap<>();
private final Set<ConnectionCallbacks> connectionCallbacks = new HashSet<>();
private final Set<OnConnectionFailedListener> connectionFailedListeners = new HashSet<>();
private final Set<String> scopes = new HashSet<>();
private String accountName;
private int clientId = -1;
private FragmentActivity fragmentActivity;
private Looper looper;
private int gravityForPopups;
private OnConnectionFailedListener unresolvedConnectionFailedListener;
private View viewForPopups;
/** /**
* Builder to help construct the {@link GoogleApiClient} object. * Builder to help construct the {@link GoogleApiClient} object.
* *
* @param context The context to use for the connection. * @param context The context to use for the connection.
*/ */
public Builder(Context context) { public Builder(Context context) {
this.context = context;
this.looper = context.getMainLooper();
} }
/** /**
@ -242,7 +263,7 @@ public interface GoogleApiClient {
* @see Api * @see Api
*/ */
public <O extends Api.ApiOptions.HasOptions> Builder addApi(Api<O> api, O options) { public <O extends Api.ApiOptions.HasOptions> Builder addApi(Api<O> api, O options) {
// TODO apis.put(api, options);
return this; return this;
} }
@ -253,7 +274,7 @@ public interface GoogleApiClient {
* @see Api * @see Api
*/ */
public Builder addApi(Api<? extends Api.ApiOptions.NotRequiredOptions> api) { public Builder addApi(Api<? extends Api.ApiOptions.NotRequiredOptions> api) {
// TODO apis.put(api, null);
return this; return this;
} }
@ -273,7 +294,7 @@ public interface GoogleApiClient {
* call are delivered. * call are delivered.
*/ */
public Builder addConnectionCallbacks(ConnectionCallbacks listener) { public Builder addConnectionCallbacks(ConnectionCallbacks listener) {
// TODO connectionCallbacks.add(listener);
return this; return this;
} }
@ -293,7 +314,7 @@ public interface GoogleApiClient {
* call are delivered. * call are delivered.
*/ */
public Builder addOnConnectionFailedListener(OnConnectionFailedListener listener) { public Builder addOnConnectionFailedListener(OnConnectionFailedListener listener) {
// TODO connectionFailedListeners.add(listener);
return this; return this;
} }
@ -305,7 +326,7 @@ public interface GoogleApiClient {
* @see com.google.android.gms.common.Scopes * @see com.google.android.gms.common.Scopes
*/ */
public Builder addScope(Scope scope) { public Builder addScope(Scope scope) {
// TODO scopes.add(scope.getScopeUri());
return this; return this;
} }
@ -315,13 +336,20 @@ public interface GoogleApiClient {
* @return The {@link GoogleApiClient} object. * @return The {@link GoogleApiClient} object.
*/ */
public GoogleApiClient build() { public GoogleApiClient build() {
return null; // TODO return new GoogleApiClientImpl(context, looper, getAccountInfo(), apis,
connectionCallbacks, connectionFailedListeners, clientId);
}
private AccountInfo getAccountInfo() {
return null;
} }
public Builder enableAutoManage(FragmentActivity fragmentActivity, int cliendId, public Builder enableAutoManage(FragmentActivity fragmentActivity, int cliendId,
OnConnectionFailedListener unresolvedConnectionFailedListener) OnConnectionFailedListener unresolvedConnectionFailedListener)
throws NullPointerException, IllegalArgumentException, IllegalStateException { throws NullPointerException, IllegalArgumentException, IllegalStateException {
// TODO this.fragmentActivity = fragmentActivity;
this.clientId = cliendId;
this.unresolvedConnectionFailedListener = unresolvedConnectionFailedListener;
return this; return this;
} }
@ -334,7 +362,7 @@ public interface GoogleApiClient {
* {@link GoogleApiClient}. * {@link GoogleApiClient}.
*/ */
public Builder setAccountName(String accountName) { public Builder setAccountName(String accountName) {
// TODO this.accountName = accountName;
return this; return this;
} }
@ -345,7 +373,7 @@ public interface GoogleApiClient {
* @param gravityForPopups The gravity which controls the placement of games service popups. * @param gravityForPopups The gravity which controls the placement of games service popups.
*/ */
public Builder setGravityForPopups(int gravityForPopups) { public Builder setGravityForPopups(int gravityForPopups) {
// TODO this.gravityForPopups = gravityForPopups;
return this; return this;
} }
@ -355,7 +383,7 @@ public interface GoogleApiClient {
* thread will be used. * thread will be used.
*/ */
public Builder setHandler(Handler handler) { public Builder setHandler(Handler handler) {
// TODO this.looper = handler.getLooper();
return this; return this;
} }
@ -365,7 +393,7 @@ public interface GoogleApiClient {
* @param viewForPopups The view to use as a content view for popups. View cannot be null. * @param viewForPopups The view to use as a content view for popups. View cannot be null.
*/ */
public Builder setViewForPopups(View viewForPopups) { public Builder setViewForPopups(View viewForPopups) {
// TODO this.viewForPopups = viewForPopups;
return this; return this;
} }
@ -373,13 +401,13 @@ public interface GoogleApiClient {
* Specify that the default account should be used when connecting to services. * Specify that the default account should be used when connecting to services.
*/ */
public Builder useDefaultAccount() { public Builder useDefaultAccount() {
// TODO this.accountName = Constants.DEFAULT_ACCOUNT;
return this; return this;
} }
} }
/** /**
* Provides callbacks that are called when the client is connected or disconnected from the * Provides callbacks that are called when the client is connected or disconnected from the
* service. Most applications implement {@link #onConnected(Bundle)} to start making requests. * service. Most applications implement {@link #onConnected(Bundle)} to start making requests.
*/ */
public interface ConnectionCallbacks { public interface ConnectionCallbacks {

View File

@ -1,8 +0,0 @@
package com.google.android.gms.common.api;
/**
* Represents the final result of invoking an API method in Google Play Services.
*/
public interface Result {
public Status getStatus();
}

View File

@ -1,13 +0,0 @@
package com.google.android.gms.common.api;
/**
* Represents the results of work.
* <p/>
* TODO: content (is this IPC API?)
*/
public final class Status implements Result {
@Override
public Status getStatus() {
return this;
}
}

View File

@ -0,0 +1,33 @@
package com.google.android.gms.location;
import android.app.PendingIntent;
import android.location.Location;
import android.os.Looper;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import org.microg.gms.Constants;
public interface FusedLocationProviderApi {
String KEY_LOCATION_CHANGED = "com.google.android.location.LOCATION";
String KEY_MOCK_LOCATION = Constants.KEY_MOCK_LOCATION;
public Location getLastLocation(GoogleApiClient client);
public PendingResult requestLocationUpdates(GoogleApiClient client, LocationRequest request,
LocationListener listener);
public PendingResult requestLocationUpdates(GoogleApiClient client, LocationRequest request,
LocationListener listener, Looper looper);
public PendingResult requestLocationUpdates(GoogleApiClient client, LocationRequest request,
PendingIntent callbackIntent);
public PendingResult removeLocationUpdates(GoogleApiClient client, LocationListener listener);
public PendingResult removeLocationUpdates(GoogleApiClient client,
PendingIntent callbackIntent);
public PendingResult setMockMode(GoogleApiClient client, boolean isMockMode);
public PendingResult setMockLocation(GoogleApiClient client, Location mockLocation);
}

View File

@ -0,0 +1,4 @@
package com.google.android.gms.location;
public interface GeofencingApi {
}

View File

@ -0,0 +1,78 @@
package com.google.android.gms.location;
import android.content.Context;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.api.GoogleApiClient;
import org.microg.gms.common.ForwardConnectionCallbacks;
import org.microg.gms.common.ForwardConnectionFailedListener;
@Deprecated
public class LocationClient implements GooglePlayServicesClient {
private GoogleApiClient googleApiClient;
public LocationClient(Context context, ConnectionCallbacks callbacks) {
googleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(new ForwardConnectionCallbacks(callbacks))
.build();
}
@Override
public void connect() {
googleApiClient.connect();
}
@Override
public void disconnect() {
googleApiClient.disconnect();
}
@Override
public boolean isConnected() {
return googleApiClient.isConnected();
}
@Override
public boolean isConnecting() {
return googleApiClient.isConnecting();
}
@Override
public void registerConnectionCallbacks(final ConnectionCallbacks listener) {
googleApiClient.registerConnectionCallbacks(new ForwardConnectionCallbacks(listener));
}
@Override
public boolean isConnectionCallbacksRegistered(ConnectionCallbacks listener) {
return googleApiClient
.isConnectionCallbacksRegistered(new ForwardConnectionCallbacks(listener));
}
@Override
public void unregisterConnectionCallbacks(
ConnectionCallbacks listener) {
googleApiClient.unregisterConnectionCallbacks(new ForwardConnectionCallbacks(listener));
}
@Override
public void registerConnectionFailedListener(
OnConnectionFailedListener listener) {
googleApiClient.registerConnectionFailedListener(
new ForwardConnectionFailedListener(listener));
}
@Override
public boolean isConnectionFailedListenerRegistered(
OnConnectionFailedListener listener) {
return googleApiClient.isConnectionFailedListenerRegistered(
new ForwardConnectionFailedListener(listener));
}
@Override
public void unregisterConnectionFailedListener(
OnConnectionFailedListener listener) {
googleApiClient.unregisterConnectionFailedListener(
new ForwardConnectionFailedListener(listener));
}
}

View File

@ -0,0 +1,4 @@
package com.google.android.gms.location;
public interface LocationListener {
}

View File

@ -0,0 +1,28 @@
package com.google.android.gms.location;
import android.content.Context;
import android.os.Looper;
import com.google.android.gms.common.api.AccountInfo;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.GoogleApiClient;
import org.microg.gms.location.FusedLocationProviderApiImpl;
import org.microg.gms.location.GeofencingApiImpl;
import org.microg.gms.location.LocationClientImpl;
/**
* The main entry point for location services integration.
*/
public class LocationServices {
public static final Api<Api.ApiOptions.NoOptions> API = new Api<>(
new Api.Builder<Api.ApiOptions.NoOptions>() {
@Override
public Api.Connection build(Context context, Looper looper,
Api.ApiOptions.NoOptions options,
AccountInfo accountInfo, GoogleApiClient.ConnectionCallbacks callbacks,
GoogleApiClient.OnConnectionFailedListener connectionFailedListener) {
return new LocationClientImpl(context);
}
});
public static final FusedLocationProviderApi FusedLocationApi = new FusedLocationProviderApiImpl();
public static final GeofencingApi GeofencingApi = new GeofencingApiImpl();
}

View File

@ -0,0 +1,35 @@
package org.microg.gms.common;
import android.os.Bundle;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationClient;
public final class ForwardConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks {
private final GooglePlayServicesClient.ConnectionCallbacks callbacks;
public ForwardConnectionCallbacks(GooglePlayServicesClient.ConnectionCallbacks callbacks) {
this.callbacks = callbacks;
}
@Override
public boolean equals(Object o) {
return o instanceof ForwardConnectionCallbacks &&
callbacks.equals(((ForwardConnectionCallbacks) o).callbacks);
}
@Override
public int hashCode() {
return callbacks.hashCode();
}
@Override
public void onConnected(Bundle connectionHint) {
callbacks.onConnected(connectionHint);
}
@Override
public void onConnectionSuspended(int cause) {
callbacks.onDisconnected();
}
}

View File

@ -0,0 +1,31 @@
package org.microg.gms.common;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.api.GoogleApiClient;
public final class ForwardConnectionFailedListener
implements GoogleApiClient.OnConnectionFailedListener {
private final GooglePlayServicesClient.OnConnectionFailedListener listener;
public ForwardConnectionFailedListener(
GooglePlayServicesClient.OnConnectionFailedListener listener) {
this.listener = listener;
}
@Override
public boolean equals(Object o) {
return o instanceof ForwardConnectionFailedListener &&
listener.equals(((ForwardConnectionFailedListener) o).listener);
}
@Override
public int hashCode() {
return listener.hashCode();
}
@Override
public void onConnectionFailed(ConnectionResult result) {
listener.onConnectionFailed(result);
}
}

View File

@ -0,0 +1,105 @@
package org.microg.gms.common;
import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.internal.IGmsCallbacks;
import com.google.android.gms.common.internal.IGmsServiceBroker;
public abstract class GmsClient<I extends IInterface> implements Api.Connection {
private static final String TAG = "GmsClient";
private final Context context;
private ConnectionState state = ConnectionState.CONNECTED;
private ServiceConnection serviceConnection;
private I serviceInterface;
public GmsClient(Context context) {
this.context = context;
}
protected abstract String getActionString();
protected abstract void onConnectedToBroker(IGmsServiceBroker broker, GmsCallbacks callbacks)
throws RemoteException;
protected abstract I interfaceFromBinder(IBinder binder);
@Override
public void connect() {
state = ConnectionState.CONNECTING;
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(context) !=
ConnectionResult.SUCCESS) {
state = ConnectionState.NOT_CONNECTED;
} else {
if (serviceConnection != null) {
MultiConnectionKeeper.getInstance(context)
.unbind(getActionString(), serviceConnection);
}
serviceConnection = new GmsServiceConnection();
MultiConnectionKeeper.getInstance(context).bind(getActionString(),
serviceConnection);
}
}
@Override
public void disconnect() {
serviceInterface = null;
if (serviceConnection != null) {
MultiConnectionKeeper.getInstance(context).unbind(getActionString(), serviceConnection);
serviceConnection = null;
}
state = ConnectionState.NOT_CONNECTED;
}
@Override
public boolean isConnected() {
return state == ConnectionState.CONNECTED;
}
public Context getContext() {
return context;
}
public I getServiceInterface() {
return serviceInterface;
}
private enum ConnectionState {
NOT_CONNECTED, CONNECTING, CONNECTED, ERROR
}
private class GmsServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
try {
onConnectedToBroker(IGmsServiceBroker.Stub.asInterface(iBinder), new GmsCallbacks());
} catch (RemoteException e) {
disconnect();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
state = ConnectionState.ERROR;
}
}
public class GmsCallbacks extends IGmsCallbacks.Stub {
@Override
public void onPostInitComplete(int statusCode, IBinder binder, Bundle params)
throws RemoteException {
serviceInterface = interfaceFromBinder(binder);
}
}
}

View File

@ -0,0 +1,136 @@
package org.microg.gms.common;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static org.microg.gms.Constants.GMS_PACKAGE_NAME;
public class MultiConnectionKeeper {
private static MultiConnectionKeeper INSTANCE;
private final Context context;
private final Map<String, Connection> connections = new HashMap<>();
public MultiConnectionKeeper(Context context) {
this.context = context;
}
public static MultiConnectionKeeper getInstance(Context context) {
if (INSTANCE == null)
INSTANCE = new MultiConnectionKeeper(context);
return INSTANCE;
}
public boolean bind(String action, ServiceConnection connection) {
Connection con = connections.get(action);
if (con != null) {
if (!con.forwardsConnection(connection)) {
con.addConnectionForward(connection);
if (!con.isBound())
con.bind();
}
} else {
con = new Connection(action);
con.addConnectionForward(connection);
con.bind();
connections.put(action, con);
}
return con.isBound();
}
public void unbind(String action, ServiceConnection connection) {
Connection con = connections.get(action);
if (con != null) {
con.removeConnectionForward(connection);
if (!con.hasForwards() && con.isBound()) {
con.unbind();
}
}
}
public class Connection {
private final String actionString;
private final Set<ServiceConnection> connectionForwards = new HashSet<>();
private boolean bound = false;
private boolean connected = false;
private IBinder binder;
private ComponentName component;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
binder = iBinder;
component = componentName;
for (ServiceConnection connection : connectionForwards) {
connection.onServiceConnected(componentName, iBinder);
}
connected = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
binder = null;
component = componentName;
for (ServiceConnection connection : connectionForwards) {
connection.onServiceDisconnected(componentName);
}
connected = false;
}
};
public Connection(String actionString) {
this.actionString = actionString;
}
public void bind() {
Intent intent = new Intent(actionString).setPackage(GMS_PACKAGE_NAME);
bound = context.bindService(intent, serviceConnection,
Context.BIND_ADJUST_WITH_ACTIVITY & Context.BIND_AUTO_CREATE);
if (!bound) {
context.unbindService(serviceConnection);
}
}
public boolean isBound() {
return bound;
}
public IBinder getBinder() {
return binder;
}
public void unbind() {
context.unbindService(serviceConnection);
bound = false;
}
public void addConnectionForward(ServiceConnection connection) {
connectionForwards.add(connection);
if (connected) {
connection.onServiceConnected(component, binder);
}
}
public void removeConnectionForward(ServiceConnection connection) {
connectionForwards.remove(connection);
if (connected) {
connection.onServiceDisconnected(component);
}
}
public boolean forwardsConnection(ServiceConnection connection) {
return connectionForwards.contains(connection);
}
public boolean hasForwards() {
return !connectionForwards.isEmpty();
}
}
}

View File

@ -0,0 +1,95 @@
package org.microg.gms.common.api;
import android.os.Looper;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Result;
import com.google.android.gms.common.api.ResultCallback;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AbstractPendingResult<R extends Result> implements PendingResult<R> {
private final Object lock = new Object();
private final CountDownLatch countDownLatch = new CountDownLatch(1);
private final CallbackHandler handler;
private boolean canceled;
private R result;
private ResultCallback<R> resultCallback;
public AbstractPendingResult(Looper looper) {
handler = new CallbackHandler(looper);
}
private R getResult() {
synchronized (lock) {
return result;
}
}
@Override
public R await() {
try {
countDownLatch.await();
} catch (InterruptedException ignored) {
}
return getResult();
}
@Override
public R await(long time, TimeUnit unit) {
try {
countDownLatch.await(time, unit);
} catch (InterruptedException ignored) {
}
return getResult();
}
@Override
public void cancel() {
// TODO
}
@Override
public boolean isCanceled() {
synchronized (lock) {
return canceled;
}
}
public boolean isReady() {
return this.countDownLatch.getCount() == 0L;
}
@Override
public void setResultCallback(ResultCallback<R> callback, long time, TimeUnit unit) {
synchronized (lock) {
if (!isCanceled()) {
if (isReady()) {
handler.sendResultCallback(callback, getResult());
} else {
handler.sendTimeoutResultCallback(this, unit.toMillis(time));
}
}
}
}
@Override
public void setResultCallback(ResultCallback<R> callback) {
synchronized (lock) {
if (!isCanceled()) {
if (isReady()) {
handler.sendResultCallback(callback, getResult());
} else {
resultCallback = callback;
}
}
}
}
private void deliverResult(R result) {
this.result = result;
countDownLatch.countDown();
}
}

View File

@ -0,0 +1,42 @@
package org.microg.gms.common.api;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import com.google.android.gms.common.api.Result;
import com.google.android.gms.common.api.ResultCallback;
class CallbackHandler<R extends Result> extends Handler {
public static final int CALLBACK_ON_COMPLETE = 1;
public static final int CALLBACK_ON_TIMEOUT = 2;
public CallbackHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case CALLBACK_ON_COMPLETE:
OnCompleteObject<R> o = (OnCompleteObject<R>) msg.obj;
o.callback.onResult(o.result);
break;
case CALLBACK_ON_TIMEOUT:
// TODO
break;
}
}
public void sendResultCallback(ResultCallback<R> callback, R result) {
}
public void sendTimeoutResultCallback(AbstractPendingResult pendingResult, long millis) {
}
public static class OnCompleteObject<R extends Result> {
public ResultCallback<R> callback;
public R result;
}
}

View File

@ -0,0 +1,155 @@
package org.microg.gms.common.api;
import android.content.Context;
import android.os.Bundle;
import android.os.Looper;
import android.support.v4.app.FragmentActivity;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public class GoogleApiClientImpl implements GoogleApiClient {
private final Context context;
private final Looper looper;
private final AccountInfo accountInfo;
private final Map<Api, Api.ApiOptions> apis = new HashMap<>();
private final Map<Api, Api.Connection> apiConnections = new HashMap<>();
private final Set<ConnectionCallbacks> connectionCallbacks = new HashSet<>();
private final Set<OnConnectionFailedListener> connectionFailedListeners = new HashSet<>();
private final ConnectionCallbacks baseConnectionCallbacks = new ConnectionCallbacks() {
@Override
public void onConnected(Bundle connectionHint) {
for (ConnectionCallbacks callback : connectionCallbacks) {
callback.onConnected(connectionHint);
}
}
@Override
public void onConnectionSuspended(int cause) {
for (ConnectionCallbacks callback : connectionCallbacks) {
callback.onConnectionSuspended(cause);
}
}
};
private final OnConnectionFailedListener baseConnectionFailedListener = new OnConnectionFailedListener() {
@Override
public void onConnectionFailed(ConnectionResult result) {
for (OnConnectionFailedListener listener : connectionFailedListeners) {
listener.onConnectionFailed(result);
}
}
};
private final int clientId;
public GoogleApiClientImpl(Context context, Looper looper, AccountInfo accountInfo,
Map<Api, Api.ApiOptions> apis,
Set<ConnectionCallbacks> connectionCallbacks,
Set<OnConnectionFailedListener> connectionFailedListeners, int clientId) {
this.context = context;
this.looper = looper;
this.accountInfo = accountInfo;
this.apis.putAll(apis);
this.connectionCallbacks.addAll(connectionCallbacks);
this.connectionFailedListeners.addAll(connectionFailedListeners);
this.clientId = clientId;
for (Api api : apis.keySet()) {
apiConnections.put(api, api.getBuilder().build(context, looper,
apis.get(api), accountInfo, baseConnectionCallbacks,
baseConnectionFailedListener));
}
}
public Api.Connection getApiConnection(Api api) {
return apiConnections.get(api);
}
@Override
public ConnectionResult blockingConnect() {
return null;
}
@Override
public ConnectionResult blockingConnect(long timeout, TimeUnit unit) {
return null;
}
@Override
public PendingResult<Status> clearDefaultAccountAndReconnect() {
return null;
}
@Override
public void connect() {
for (Api.Connection connection : apiConnections.values()) {
connection.connect();
}
}
@Override
public void disconnect() {
for (Api.Connection connection : apiConnections.values()) {
connection.disconnect();
}
}
@Override
public boolean isConnected() {
for (Api.Connection connection : apiConnections.values()) {
if (!connection.isConnected()) return false;
}
return true;
}
@Override
public boolean isConnecting() {
return false; // TODO
}
@Override
public boolean isConnectionCallbacksRegistered(ConnectionCallbacks listener) {
return connectionCallbacks.contains(listener);
}
@Override
public boolean isConnectionFailedListenerRegistered(
OnConnectionFailedListener listener) {
return connectionFailedListeners.contains(listener);
}
@Override
public void reconnect() {
disconnect();
connect();
}
@Override
public void registerConnectionCallbacks(ConnectionCallbacks listener) {
connectionCallbacks.add(listener);
}
@Override
public void registerConnectionFailedListener(OnConnectionFailedListener listener) {
connectionFailedListeners.add(listener);
}
@Override
public void stopAutoManager(FragmentActivity lifecycleActivity) throws IllegalStateException {
}
@Override
public void unregisterConnectionCallbacks(ConnectionCallbacks listener) {
connectionCallbacks.remove(listener);
}
@Override
public void unregisterConnectionFailedListener(OnConnectionFailedListener listener) {
connectionFailedListeners.remove(listener);
}
}

View File

@ -0,0 +1,72 @@
package org.microg.gms.location;
import android.app.PendingIntent;
import android.location.Location;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.location.FusedLocationProviderApi;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
public class FusedLocationProviderApiImpl implements FusedLocationProviderApi {
private static final String TAG = "GmsFusedApiImpl";
@Override
public Location getLastLocation(GoogleApiClient client) {
try {
return LocationClientImpl.get(client).getLastLocation();
} catch (RemoteException e) {
Log.w(TAG, e);
return null;
}
}
@Override
public PendingResult requestLocationUpdates(GoogleApiClient client, LocationRequest request,
LocationListener listener) {
//LocationClientImpl.get(client).requestLocationUpdates(request, listener);
return null;
}
@Override
public PendingResult requestLocationUpdates(GoogleApiClient client, LocationRequest request,
LocationListener listener, Looper looper) {
//LocationClientImpl.get(client).requestLocationUpdates(request, listener, looper);
return null;
}
@Override
public PendingResult requestLocationUpdates(GoogleApiClient client, LocationRequest request,
PendingIntent callbackIntent) {
//LocationClientImpl.get(client).requestLocationUpdates(request, callbackIntent);
return null;
}
@Override
public PendingResult removeLocationUpdates(GoogleApiClient client, LocationListener listener) {
//LocationClientImpl.get(client).removeLocationUpdates(listener);
return null;
}
@Override
public PendingResult removeLocationUpdates(GoogleApiClient client,
PendingIntent callbackIntent) {
//LocationClientImpl.get(client).removeLocationUpdates(callbackIntent);
return null;
}
@Override
public PendingResult setMockMode(GoogleApiClient client, boolean isMockMode) {
//LocationClientImpl.get(client).setMockMode(isMockMode);
return null;
}
@Override
public PendingResult setMockLocation(GoogleApiClient client, Location mockLocation) {
//LocationClientImpl.get(client).setMockLocation(mockLocation);
return null;
}
}

View File

@ -0,0 +1,6 @@
package org.microg.gms.location;
import com.google.android.gms.location.GeofencingApi;
public class GeofencingApiImpl implements GeofencingApi {
}

View File

@ -0,0 +1,35 @@
package org.microg.gms.location;
import android.content.Context;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import com.google.android.gms.common.internal.IGmsServiceBroker;
import com.google.android.gms.location.internal.IGoogleLocationManagerService;
import org.microg.gms.Constants;
import org.microg.gms.common.GmsClient;
public class GoogleLocationManagerClient extends GmsClient<IGoogleLocationManagerService> {
public GoogleLocationManagerClient(Context context) {
super(context);
}
@Override
protected String getActionString() {
return Constants.ACTION_GMS_LOCATION_MANAGER_SERVICE_START;
}
@Override
protected IGoogleLocationManagerService interfaceFromBinder(IBinder binder) {
return IGoogleLocationManagerService.Stub.asInterface(binder);
}
@Override
protected void onConnectedToBroker(IGmsServiceBroker broker, GmsCallbacks callbacks)
throws RemoteException {
Bundle bundle = new Bundle();
bundle.putString("client_name", "locationServices");
broker.getGoogleLocationManagerService(callbacks, Constants.MAX_REFERENCE_VERSION,
getContext().getPackageName(), bundle);
}
}

View File

@ -0,0 +1,61 @@
package org.microg.gms.location;
import android.app.PendingIntent;
import android.content.Context;
import android.location.Location;
import android.os.Looper;
import android.os.RemoteException;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import org.microg.gms.common.api.GoogleApiClientImpl;
public class LocationClientImpl extends GoogleLocationManagerClient {
public LocationClientImpl(Context context) {
super(context);
}
public static LocationClientImpl get(GoogleApiClient apiClient) {
if (apiClient instanceof GoogleApiClientImpl) {
return (LocationClientImpl) ((GoogleApiClientImpl) apiClient)
.getApiConnection(LocationServices.API);
}
return null;
}
public Location getLastLocation() throws RemoteException {
return getServiceInterface().getLastLocation();
}
public void requestLocationUpdates(LocationRequest request, LocationListener listener)
throws RemoteException {
}
public void requestLocationUpdates(LocationRequest request, PendingIntent pendingIntent)
throws RemoteException {
}
public void requestLocationUpdates(LocationRequest request, LocationListener listener,
Looper looper) throws RemoteException {
}
public void removeLocationUpdates(LocationListener listener) throws RemoteException {
}
public void removeLocationUpdates(PendingIntent pendingIntent) throws RemoteException {
}
public void setMockMode(boolean isMockMode) throws RemoteException {
}
public void setMockLocation(Location mockLocation) throws RemoteException {
}
}