Restructure modules 18c3a6154d

This commit is contained in:
inotia00 2023-12-22 20:11:04 +09:00 • committed by Cuynu
commit b19fad1281
35 changed files with 2204 additions and 21 deletions

View file

@ -4,7 +4,13 @@
*/
buildscript {
<<<<<<< HEAD
ext.kotlinVersion = '1.8.20'
=======
ext.safeParcelVersion = '1.7.1'
ext.kotlinVersion = '1.7.21'
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
ext.coroutineVersion = '1.6.4'
ext.annotationVersion = '1.6.0'
@ -65,4 +71,17 @@ subprojects {
mavenCentral()
google()
}
<<<<<<< HEAD
}
=======
afterEvaluate {
// Temporary hack for Android Studio
if (project.plugins.hasPlugin('com.android.base')) {
dependencies {
compileOnly "org.microg:safe-parcel:$safeParcelVersion"
testCompileOnly "org.microg:safe-parcel:$safeParcelVersion"
}
}
}
}
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)

View file

@ -50,4 +50,196 @@ public class GoogleApiAvailability {
return null;
}
<<<<<<< HEAD
=======
/**
* Returns a PendingIntent to address the provided connection failure.
* <p/>
* If {@link ConnectionResult#hasResolution()} is true, then {@link ConnectionResult#getResolution()}
* will be returned. Otherwise, the returned PendingIntent will direct the user to either the
* Play Store if Google Play services is out of date or missing, or system settings if Google
* Play services is disabled on the device.
*
* @param context parent context for creating the PendingIntent.
* @param result the connection failure. If successful or the error is not resolvable by the user, null is returned.
*/
public PendingIntent getErrorResolutionPendingIntent(Context context, ConnectionResult result) {
if (result.hasResolution()) {
return result.getResolution();
}
return getErrorResolutionPendingIntent(context, result.getErrorCode(), 0);
}
/**
* Returns a PendingIntent to address the provided errorCode. It will direct the user to either
* the Play Store if Google Play services is out of date or missing, or system settings if
* Google Play services is disabled on the device.
*
* @param context parent context for creating the PendingIntent.
* @param errorCode error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.
* If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.
* @param requestCode The requestCode given when calling startActivityForResult.
*/
public PendingIntent getErrorResolutionPendingIntent(Context context, int errorCode, int requestCode) {
// TODO
return null;
}
/**
* Returns a human-readable string of the error code returned from {@link #isGooglePlayServicesAvailable(Context)}.
*/
public final String getErrorString(int errorCode) {
return ConnectionResult.getStatusString(errorCode);
}
/**
* Verifies that Google Play services is installed and enabled on this device, and that the
* version installed on this device is no older than the one required by this client.
*
* @return status code indicating whether there was an error. Can be one of following in
* {@link ConnectionResult}: SUCCESS, SERVICE_MISSING, SERVICE_UPDATING,
* SERVICE_VERSION_UPDATE_REQUIRED, SERVICE_DISABLED, SERVICE_INVALID
*/
public int isGooglePlayServicesAvailable(Context context) {
Log.d(TAG, "As we can't know right now if the later desired feature is available, " +
"we just pretend it to be.");
return SUCCESS;
}
/**
* Verifies that Google Play services is installed and enabled on this device, and that the version installed on
* this device is no older than the one required by this client or the version is not older than the one specified
* in <code>minApkVersion</code>.
*
* @return status code indicating whether there was an error. Can be one of following in
* {@link ConnectionResult}: SUCCESS, SERVICE_MISSING, SERVICE_UPDATING,
* SERVICE_VERSION_UPDATE_REQUIRED, SERVICE_DISABLED, SERVICE_INVALID
*/
public int isGooglePlayServicesAvailable(Context context, int minApkVersion) {
return isGooglePlayServicesAvailable(context);
}
/**
* Determines whether an error can be resolved via user action. If true, proceed by calling
* {@link #getErrorDialog(Activity, int, int)} and showing the dialog.
*
* @param errorCode error code returned by {@link #isGooglePlayServicesAvailable(Context)}, or
* returned to your application via {@link OnConnectionFailedListener#onConnectionFailed(ConnectionResult)}
* @return true if the error is resolvable with {@link #getErrorDialog(Activity, int, int)}
*/
public final boolean isUserResolvableError(int errorCode) {
switch (errorCode) {
case SERVICE_MISSING:
case SERVICE_VERSION_UPDATE_REQUIRED:
case SERVICE_DISABLED:
case SERVICE_INVALID:
return true;
case SIGN_IN_REQUIRED:
case INVALID_ACCOUNT:
case RESOLUTION_REQUIRED:
case NETWORK_ERROR:
case INTERNAL_ERROR:
default:
return false;
}
}
/**
* Attempts to make Google Play services available on this device. If Play Services is already
* available, the returned {@link Task} may complete immediately.
* <p/>
* If it is necessary to display UI in order to complete this request (e.g. sending the user
* to the Google Play store) the passed {@link Activity} will be used to display this UI.
* <p/>
* It is recommended to call this method from {@link Activity#onCreate(Bundle)}.
* If the passed {@link Activity} completes before the returned {@link Task} completes, the
* Task will fail with a {@link java.util.concurrent.CancellationException}.
* <p/>
* This method must be called from the main thread.
*
* @return A {@link Task}. If this Task completes without throwing an exception, Play Services
* is available on this device.
*/
public Task<Void> makeGooglePlayServicesAvailable(Activity activity) {
int status = isGooglePlayServicesAvailable(activity);
if (status == SUCCESS) {
return Tasks.forResult(null);
}
// TODO
return Tasks.forResult(null);
}
/**
* Displays a DialogFragment for an error code returned by {@link #isGooglePlayServicesAvailable(Context)}.
*
* @param activity parent activity for creating the dialog, also used for identifying language to display dialog in.
* @param errorCode error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.
* If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.
* @param requestCode The requestCode given when calling startActivityForResult.
* @return true if the dialog is shown, false otherwise
* @throws RuntimeException if API level is below 11 and activity is not a {@link FragmentActivity}.
* @see ErrorDialogFragment
* @see SupportErrorDialogFragmet
*/
public boolean showErrorDialogFragment(Activity activity, int errorCode, int requestCode) {
return showErrorDialogFragment(activity, errorCode, requestCode, null);
}
/**
* Displays a DialogFragment for an error code returned by {@link #isGooglePlayServicesAvailable(Context)}.
*
* @param activity parent activity for creating the dialog, also used for identifying language to display dialog in.
* @param errorCode error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.
* If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.
* @param requestCode The requestCode given when calling startActivityForResult.
* @param cancelListener The {@link DialogInterface.OnCancelListener} to invoke if the dialog is canceled.
* @return true if the dialog is shown, false otherwise
* @throws RuntimeException if API level is below 11 and activity is not a {@link FragmentActivity}.
*/
public boolean showErrorDialogFragment(Activity activity, int errorCode, int requestCode, DialogInterface.OnCancelListener cancelListener) {
Dialog dialog = getErrorDialog(activity, errorCode, requestCode, cancelListener);
if (dialog == null) {
return false;
} else {
// TODO
return false;
}
}
/**
* Displays a notification for an error code returned from
* {@link #isGooglePlayServicesAvailable(Context)}, if it is resolvable by the user.
* <p/>
* This method is similar to {@link #getErrorDialog(int, android.app.Activity, int)}, but is
* provided for background tasks that cannot or should not display dialogs.
*
* @param errorCode error code returned by {@link #isGooglePlayServicesAvailable(Context)} call.
* If errorCode is {@link ConnectionResult#SUCCESS} then null is returned.
* @param context used for identifying language to display dialog in as well as accessing the
* {@link android.app.NotificationManager}.
*/
public void showErrorNotification(Context context, int errorCode) {
if (errorCode == RESOLUTION_REQUIRED) {
Log.e(TAG, "showErrorNotification(context, errorCode) is called for RESOLUTION_REQUIRED when showErrorNotification(context, result) should be called");
}
if (isUserResolvableError(errorCode)) {
GooglePlayServicesUtil.showErrorNotification(errorCode, context);
}
}
/**
* Displays a notification for a connection failure, if it is resolvable by the user.
*
* @param context The calling context used to display the notification.
* @param result The connection failure. If successful or the error is not resolvable by the
* user, no notification is shown.
*/
public void showErrorNotification(Context context, ConnectionResult result) {
PendingIntent pendingIntent = getErrorResolutionPendingIntent(context, result);
if (pendingIntent != null) {
// TODO
}
}
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
}

View file

@ -20,5 +20,5 @@ import org.microg.safeparcel.AutoSafeParcelable;
@Deprecated
public class AccountInfo extends AutoSafeParcelable {
public static final Creator<AccountInfo> CREATOR = new AutoCreator<>(AccountInfo.class);
public static final Creator<AccountInfo> CREATOR = new AutoCreator<AccountInfo>(AccountInfo.class);
}

View file

@ -16,6 +16,14 @@
package com.google.android.gms.common.api;
<<<<<<< HEAD
=======
import android.accounts.Account;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import org.microg.gms.common.Hide;
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
import org.microg.gms.common.PublicApi;
import org.microg.gms.common.api.ApiClientBuilder;
@ -67,4 +75,14 @@ public final class Api<O extends Api.ApiOptions> {
}
@Hide
public interface Client {
void connect();
void disconnect();
boolean isConnected();
boolean isConnecting();
}
}

View file

@ -7,22 +7,62 @@ package com.google.android.gms.common.api;
import android.content.Context;
<<<<<<< HEAD
=======
import com.google.android.gms.common.api.internal.ApiKey;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.TaskCompletionSource;
import org.microg.gms.common.Hide;
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
import org.microg.gms.common.PublicApi;
import org.microg.gms.common.api.GoogleApiManager;
@PublicApi
<<<<<<< HEAD
public abstract class GoogleApi<O extends Api.ApiOptions> implements HasApiKey {
@PublicApi(exclude = true)
=======
public abstract class GoogleApi<O extends Api.ApiOptions> implements HasApiKey<O> {
private GoogleApiManager manager;
@Hide
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
public Api<O> api;
@Hide
public O options;
@PublicApi(exclude = true)
protected GoogleApi(Context context, Api<O> api) {
this.api = api;
<<<<<<< HEAD
GoogleApiManager.getInstance();
=======
this.manager = GoogleApiManager.getInstance(context);
}
@PublicApi(exclude = true)
protected GoogleApi(Context context, Api<O> api, O options) {
this.api = api;
this.manager = GoogleApiManager.getInstance(context);
this.options = options;
}
@PublicApi(exclude = true)
protected <R, A extends Api.Client> Task<R> scheduleTask(PendingGoogleApiCall<R, A> apiCall) {
TaskCompletionSource<R> completionSource = new TaskCompletionSource<>();
manager.scheduleTask(this, apiCall, completionSource);
return completionSource.getTask();
}
@Override
@PublicApi(exclude = true)
public ApiKey<O> getApiKey() {
return null;
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
}
@PublicApi(exclude = true)
public O getOptions() {
return null;
return options;
}
}

View file

@ -1,6 +1,34 @@
<<<<<<< HEAD
package com.google.android.gms.common.api;
import android.app.Activity;
public class GoogleApiActivity extends Activity {
=======
/*
* SPDX-FileCopyrightText: 2020, microG Project Team
* SPDX-License-Identifier: Apache-2.0
* Notice: Portions of this file are reproduced from work created and shared by Google and used
* according to terms described in the Creative Commons 4.0 Attribution License.
* See https://developers.google.com/readme/policies for details.
*/
package com.google.android.gms.common.api;
import android.app.Activity;
import android.content.DialogInterface;
import org.microg.gms.common.PublicApi;
/**
* Helper activity used by Google Play services APIs to display resolutions for connection errors.
*/
@PublicApi
public class GoogleApiActivity extends Activity implements DialogInterface.OnCancelListener {
@Override
@PublicApi(exclude = true)
public void onCancel(DialogInterface dialog) {
}
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
}

View file

@ -111,7 +111,7 @@ public interface GoogleApiClient {
* @see #registerConnectionFailedListener(OnConnectionFailedListener)
* @see #unregisterConnectionFailedListener(OnConnectionFailedListener)
*/
boolean isConnectionFailedListenerRegistered(OnConnectionFailedListener listener);
public boolean isConnectionFailedListenerRegistered(OnConnectionFailedListener listener);
/**
* Registers a listener to receive connection events from this {@link GoogleApiClient}. If the
@ -150,7 +150,7 @@ public interface GoogleApiClient {
* @param listener the listener where the results of the asynchronous {@link #connect()} call
* are delivered.
*/
void registerConnectionFailedListener(OnConnectionFailedListener listener);
public void registerConnectionFailedListener(OnConnectionFailedListener listener);
/**
* Removes a connection listener from this {@link GoogleApiClient}. Note that removing a
@ -166,10 +166,24 @@ public interface GoogleApiClient {
@PublicApi
class Builder {
private final Context context;
<<<<<<< HEAD
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 Looper looper;
=======
private final Map<Api, Api.ApiOptions> apis = new HashMap<Api, Api.ApiOptions>();
private final Set<ConnectionCallbacks> connectionCallbacks = new HashSet<ConnectionCallbacks>();
private final Set<OnConnectionFailedListener> connectionFailedListeners = new HashSet<OnConnectionFailedListener>();
private final Set<String> scopes = new HashSet<String>();
private String accountName;
private int clientId = -1;
private FragmentActivity fragmentActivity;
private Looper looper;
private int gravityForPopups;
private OnConnectionFailedListener unresolvedConnectionFailedListener;
private View viewForPopups;
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
public Builder(Context context) {
this.context = context;
@ -198,7 +212,12 @@ public interface GoogleApiClient {
}
private ApiClientSettings getClientSettings() {
return null;
ApiClientSettings clientSettings = new ApiClientSettings();
clientSettings.accountName = accountName;
clientSettings.scopes = new HashSet<>(scopes);
clientSettings.gravityForPopups = gravityForPopups;
clientSettings.viewForPopups = viewForPopups;
return clientSettings;
}
}
@ -210,6 +229,19 @@ public interface GoogleApiClient {
@PublicApi
@Deprecated
interface ConnectionCallbacks extends org.microg.gms.common.api.ConnectionCallbacks {
<<<<<<< HEAD
=======
/**
* A suspension cause informing that the service has been killed.
*/
int CAUSE_SERVICE_DISCONNECTED = 1;
/**
* A suspension cause informing you that a peer device connection was lost.
*/
int CAUSE_NETWORK_LOST = 2;
void onConnected(Bundle connectionHint);
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
}
@PublicApi

View file

@ -16,5 +16,48 @@
package com.google.android.gms.common.api;
<<<<<<< HEAD
public interface PendingResult {
=======
import java.util.concurrent.TimeUnit;
/**
* Represents a pending result from calling an API method in Google Play services. The final result
* object from a PendingResult is of type R, which can be retrieved in one of two ways.
* <p/>
* <ul>
* <li>via blocking calls to {@link #await()}, or {@link #await(long, TimeUnit)}, or</li>
* <li>via a callback by passing in an object implementing interface {@link ResultCallback} to
* {@link #setResultCallback(ResultCallback)}.</li>
* </ul>
* After the result has been retrieved using {@link #await()} or delivered to the result callback,
* it is an error to attempt to retrieve the result again. It is the responsibility of the caller
* or callback receiver to release any resources associated with the returned result. Some result
* types may implement {@link Releasable}, in which case {@link Releasable#release()} should be
* used to free the associated resources.
* <p/>
* TODO: Docs
*/
public interface PendingResult<R extends Result> {
/**
* Blocks until the task is completed. This is not allowed on the UI thread. The returned
* result object can have an additional failure mode of INTERRUPTED.
*/
public R await();
/**
* Blocks until the task is completed or has timed out waiting for the result. This is not
* allowed on the UI thread. The returned result object can have an additional failure mode
* of either INTERRUPTED or TIMEOUT.
*/
public R await(long time, TimeUnit unit);
public void cancel();
public boolean isCanceled();
public void setResultCallback(ResultCallback<R> callback, long time, TimeUnit unit);
public void setResultCallback(ResultCallback<R> callback);
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) 2013-2017 microG Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.microg.gms.common;
import com.google.android.gms.common.api.Api;
public class DummyApiClient implements Api.Client {
private boolean connected = false;
@Override
public void connect() {
connected = true;
}
@Override
public void disconnect() {
connected = false;
}
@Override
public boolean isConnected() {
return connected;
}
@Override
public boolean isConnecting() {
return false;
}
}

View file

@ -0,0 +1,204 @@
/*
* Copyright (C) 2013-2017 microG Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.microg.gms.common;
import android.accounts.Account;
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 android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.common.internal.ConnectionInfo;
import com.google.android.gms.common.internal.GetServiceRequest;
import com.google.android.gms.common.internal.IGmsCallbacks;
import com.google.android.gms.common.internal.IGmsServiceBroker;
import org.microg.gms.common.api.ConnectionCallbacks;
import org.microg.gms.common.api.OnConnectionFailedListener;
public abstract class GmsClient<I extends IInterface> implements Api.Client {
private static final String TAG = "GmsClient";
private final Context context;
protected final ConnectionCallbacks callbacks;
protected final OnConnectionFailedListener connectionFailedListener;
protected ConnectionState state = ConnectionState.NOT_CONNECTED;
private ServiceConnection serviceConnection;
private I serviceInterface;
private final String actionString;
protected boolean requireMicrog;
protected String packageName;
protected int serviceId = -1;
protected Account account = null;
protected Bundle extras = new Bundle();
public GmsClient(Context context, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener, String actionString) {
this.context = context;
this.callbacks = callbacks;
this.connectionFailedListener = connectionFailedListener;
this.actionString = actionString;
this.requireMicrog = false;
this.packageName = context.getPackageName();
}
protected void onConnectedToBroker(IGmsServiceBroker broker, GmsCallbacks callbacks) throws RemoteException {
if (serviceId == -1) {
throw new IllegalStateException("Service ID not set in constructor and onConnectedToBroker not implemented");
}
GetServiceRequest request = new GetServiceRequest(serviceId);
request.packageName = packageName;
request.account = account;
request.extras = extras;
broker.getService(callbacks, request);
}
protected abstract I interfaceFromBinder(IBinder binder);
@Override
public synchronized void connect() {
Log.d(TAG, "connect()");
if (state == ConnectionState.CONNECTED || state == ConnectionState.CONNECTING) {
Log.d(TAG, "Already connected/connecting - nothing to do");
}
state = ConnectionState.CONNECTING;
if (serviceConnection != null) {
MultiConnectionKeeper.getInstance(context).unbind(actionString, serviceConnection);
}
serviceConnection = new GmsServiceConnection();
if (!MultiConnectionKeeper.getInstance(context).bind(actionString, serviceConnection, requireMicrog)) {
state = ConnectionState.ERROR;
handleConnectionFailed();
}
}
public void handleConnectionFailed() {
connectionFailedListener.onConnectionFailed(new ConnectionResult(ConnectionResult.API_UNAVAILABLE, null));
}
@Override
public synchronized void disconnect() {
Log.d(TAG, "disconnect()");
if (state == ConnectionState.DISCONNECTING) return;
if (state == ConnectionState.CONNECTING) {
state = ConnectionState.DISCONNECTING;
return;
}
serviceInterface = null;
if (serviceConnection != null) {
MultiConnectionKeeper.getInstance(context).unbind(actionString, serviceConnection);
serviceConnection = null;
}
state = ConnectionState.NOT_CONNECTED;
}
@Override
public synchronized boolean isConnected() {
return (state == ConnectionState.CONNECTED && serviceInterface != null && serviceInterface.asBinder().isBinderAlive() ) || state == ConnectionState.PSEUDO_CONNECTED;
}
@Override
public synchronized boolean isConnecting() {
return state == ConnectionState.CONNECTING;
}
public synchronized boolean hasError() {
return state == ConnectionState.ERROR;
}
public Context getContext() {
return context;
}
public synchronized I getServiceInterface() {
if (isConnecting()) {
// TODO: wait for connection to be established and return afterwards.
throw new IllegalStateException("Waiting for connection");
} else if (!isConnected()) {
throw new IllegalStateException("interface only available once connected!");
}
return serviceInterface;
}
protected enum ConnectionState {
NOT_CONNECTED, CONNECTING, CONNECTED, DISCONNECTING, ERROR, PSEUDO_CONNECTED
}
private class GmsServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
try {
Log.d(TAG, "ServiceConnection : onServiceConnected(" + componentName + ")");
onConnectedToBroker(IGmsServiceBroker.Stub.asInterface(iBinder), new GmsCallbacks());
} catch (RemoteException e) {
disconnect();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
synchronized (GmsClient.this) {
state = ConnectionState.NOT_CONNECTED;
}
}
}
public class GmsCallbacks extends IGmsCallbacks.Stub {
@Override
public void onPostInitComplete(int statusCode, IBinder binder, Bundle params)
throws RemoteException {
if (statusCode != CommonStatusCodes.SUCCESS) {
state = ConnectionState.CONNECTED;
disconnect();
connectionFailedListener.onConnectionFailed(new ConnectionResult(statusCode));
} else {
synchronized (GmsClient.this) {
if (state == ConnectionState.DISCONNECTING) {
state = ConnectionState.CONNECTED;
disconnect();
return;
}
state = ConnectionState.CONNECTED;
serviceInterface = interfaceFromBinder(binder);
}
Log.d(TAG, "GmsCallbacks : onPostInitComplete(" + serviceInterface + ")");
callbacks.onConnected(params);
}
}
@Override
public void onAccountValidationComplete(int statusCode, Bundle params) throws RemoteException {
Log.d(TAG, "GmsCallbacks : onAccountValidationComplete");
}
@Override
public void onPostInitCompleteWithConnectionInfo(int statusCode, IBinder binder, ConnectionInfo info) throws RemoteException {
onPostInitComplete(statusCode, binder, info == null ? null : info.params);
}
}
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (C) 2013-2017 microG Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.microg.gms.common;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Result;
import org.microg.gms.common.api.AbstractPendingResult;
import org.microg.gms.common.api.GoogleApiClientImpl;
public class GmsConnector<C extends Api.Client, R extends Result> {
private static final String TAG = "GmsConnector";
private final GoogleApiClientImpl apiClient;
private final Api api;
private final Callback<C, R> callback;
public GmsConnector(GoogleApiClient apiClient, Api api, Callback<C, R> callback) {
this.apiClient = (GoogleApiClientImpl) apiClient;
this.api = api;
this.callback = callback;
}
public static <C extends Api.Client, R extends Result> PendingResult<R> call(GoogleApiClient client, Api api, GmsConnector.Callback<C, R> callback) {
return new GmsConnector<C, R>(client, api, callback).connect();
}
public AbstractPendingResult<R> connect() {
Log.d(TAG, "connect()");
apiClient.incrementUsageCounter();
apiClient.getApiConnection(api);
Looper looper = apiClient.getLooper();
final AbstractPendingResult<R> result = new AbstractPendingResult<R>(looper);
Message msg = new Message();
msg.obj = result;
new Handler(looper).sendMessage(msg);
return result;
}
public interface Callback<C, R> {
void onClientAvailable(C client, ResultProvider<R> resultProvider) throws RemoteException;
interface ResultProvider<R> {
void onResultAvailable(R result);
}
}
private class Handler extends android.os.Handler {
private Handler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "Handler : handleMessage");
final AbstractPendingResult<R> result = (AbstractPendingResult<R>) msg.obj;
try {
C connection = (C) apiClient.getApiConnection(api);
callback.onClientAvailable(connection, new GmsConnector.Callback.ResultProvider<R>() {
@Override
public void onResultAvailable(R realResult) {
result.deliverResult(realResult);
apiClient.decrementUsageCounter();
}
});
} catch (RemoteException ignored) {
}
}
}
}

View file

@ -0,0 +1,229 @@
/*
* Copyright (C) 2013-2017 microG Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.microg.gms.common;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.os.IBinder;
import android.util.Log;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
public class MultiConnectionKeeper {
private static final String TAG = "GmsMultiConKeeper";
private static MultiConnectionKeeper INSTANCE;
private final Context context;
private final Map<String, Connection> connections = new HashMap<String, Connection>();
public MultiConnectionKeeper(Context context) {
this.context = context;
}
public synchronized static MultiConnectionKeeper getInstance(Context context) {
if (INSTANCE == null)
INSTANCE = new MultiConnectionKeeper(context.getApplicationContext());
return INSTANCE;
}
public synchronized boolean bind(String action, ServiceConnection connection) {
return bind(action, connection, false);
}
public synchronized boolean bind(String action, ServiceConnection connection, boolean requireMicrog) {
Connection con = connections.get(action);
Log.d(TAG, "bind(" + action + ", " + connection + ", " + requireMicrog + ") has=" + (con != null));
if (con != null) {
if (!con.forwardsConnection(connection)) {
con.addConnectionForward(connection);
if (!con.isBound())
con.bind();
}
} else {
con = new Connection(action, requireMicrog);
con.addConnectionForward(connection);
con.bind();
connections.put(action, con);
}
Log.d(TAG, "bind() : bound=" + con.isBound());
return con.isBound();
}
public synchronized void unbind(String action, ServiceConnection connection) {
Log.d(TAG, "unbind(" + action + ", " + connection + ")");
Connection con = connections.get(action);
if (con != null) {
con.removeConnectionForward(connection);
if (con.isBound()) {
if (!con.hasForwards()) {
con.unbind();
connections.remove(action);
} else {
Log.d(TAG, "Not unbinding for " + connection + ": has pending other bindings on action " + action);
}
}
}
}
public class Connection {
private final String actionString;
private final boolean requireMicrog;
private final Set<ServiceConnection> connectionForwards = new HashSet<ServiceConnection>();
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) {
Log.d(TAG, "Connection(" + actionString + ") : ServiceConnection : " +
"onServiceConnected(" + componentName + ")");
binder = iBinder;
component = componentName;
for (ServiceConnection connection : connectionForwards) {
connection.onServiceConnected(componentName, iBinder);
}
connected = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d(TAG, "Connection(" + actionString + ") : ServiceConnection : " +
"onServiceDisconnected(" + componentName + ")");
binder = null;
component = componentName;
for (ServiceConnection connection : connectionForwards) {
connection.onServiceDisconnected(componentName);
}
connected = false;
bound = false;
}
};
public Connection(String actionString) {
this(actionString, false);
}
public Connection(String actionString, boolean requireMicrog) {
this.actionString = actionString;
this.requireMicrog = requireMicrog;
}
@SuppressLint("InlinedApi")
public void bind() {
Log.d(TAG, "Connection(" + actionString + ") : bind()");
Intent gmsIntent = new Intent(actionString).setPackage(GMS_PACKAGE_NAME);
Intent selfIntent = new Intent(actionString).setPackage(context.getPackageName());
Intent intent;
ResolveInfo resolveInfo;
if ((resolveInfo = context.getPackageManager().resolveService(gmsIntent, 0)) == null) {
Log.w(TAG, "No GMS service found for " + actionString);
if (context.getPackageManager().resolveService(selfIntent, 0) != null) {
Log.d(TAG, "Found service for " + actionString + " in self package, using it instead");
intent = selfIntent;
} else {
return;
}
} else if (requireMicrog && !isMicrog(resolveInfo)) {
Log.w(TAG, "GMS service found for " + actionString + " but looks not like microG");
if (context.getPackageManager().resolveService(selfIntent, 0) != null) {
Log.d(TAG, "Found service for " + actionString + " in self package, using it instead");
intent = selfIntent;
} else {
intent = gmsIntent;
}
} else {
intent = gmsIntent;
}
int flags = Context.BIND_AUTO_CREATE | Context.BIND_DEBUG_UNBIND;
if (SDK_INT >= ICE_CREAM_SANDWICH) {
flags |= Context.BIND_ADJUST_WITH_ACTIVITY;
}
bound = context.bindService(intent, serviceConnection, flags);
Log.d(TAG, "Connection(" + actionString + ") : bind() : bindService=" + bound);
if (!bound) {
context.unbindService(serviceConnection);
}
}
public boolean isMicrog(ResolveInfo resolveInfo) {
if (resolveInfo == null || resolveInfo.serviceInfo == null) return false;
if (resolveInfo.serviceInfo.name.startsWith("org.microg.")) return true;
try {
PermissionInfo info = context.getPackageManager().getPermissionInfo("org.microg.gms.EXTENDED_ACCESS", 0);
return info.packageName.equals(resolveInfo.serviceInfo.packageName);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
public boolean isBound() {
return bound;
}
public IBinder getBinder() {
return binder;
}
public void unbind() {
Log.d(TAG, "Connection(" + actionString + ") : unbind()");
try {
context.unbindService(serviceConnection);
} catch (IllegalArgumentException e) { // not bound (whatever reason)
Log.w(TAG, e);
}
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

@ -23,7 +23,11 @@ import com.google.android.gms.common.api.PendingResult;
public class AbstractPendingResult implements PendingResult {
public AbstractPendingResult(Looper looper) {
<<<<<<< HEAD
new ResultCallbackHandler<>(looper);
=======
handler = new ResultCallbackHandler<R>(looper);
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
}
}

View file

@ -22,5 +22,5 @@ import android.os.Looper;
import com.google.android.gms.common.api.Api;
public interface ApiClientBuilder<O extends Api.ApiOptions> {
ApiClient build(O options, Context context, Looper looper, ApiClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener);
Api.Client build(O options, Context context, Looper looper, ApiClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener);
}

View file

@ -5,5 +5,15 @@
package org.microg.gms.common.api;
import android.view.View;
import java.util.Set;
public class ApiClientSettings {
public String accountName;
public String packageName;
public Integer sessionId;
public Set<String> scopes;
public int gravityForPopups;
public View viewForPopups;
}

View file

@ -19,8 +19,15 @@ package org.microg.gms.common.api;
import android.content.Context;
import android.os.Bundle;
import android.os.Looper;
<<<<<<< HEAD
=======
import androidx.fragment.app.FragmentActivity;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.GoogleApiClient;
@ -32,9 +39,48 @@ import java.util.Set;
public class GoogleApiClientImpl implements GoogleApiClient {
private static final String TAG = "GmsApiClientImpl";
<<<<<<< HEAD
private final Map<Api, ApiClient> apiConnections = new HashMap<>();
private final Set<ConnectionCallbacks> connectionCallbacks = new HashSet<>();
private final Set<OnConnectionFailedListener> connectionFailedListeners = new HashSet<>();
=======
private final Context context;
private final Looper looper;
private final ApiClientSettings clientSettings;
private final Map<Api, Api.ApiOptions> apis = new HashMap<Api, Api.ApiOptions>();
private final Map<Api, Api.Client> apiConnections = new HashMap<Api, Api.Client>();
private final Set<ConnectionCallbacks> connectionCallbacks = new HashSet<ConnectionCallbacks>();
private final Set<OnConnectionFailedListener> connectionFailedListeners = new HashSet<OnConnectionFailedListener>();
private final int clientId;
private final ConnectionCallbacks baseConnectionCallbacks = new ConnectionCallbacks() {
@Override
public void onConnected(Bundle connectionHint) {
Log.d(TAG, "ConnectionCallbacks : onConnected()");
for (ConnectionCallbacks callback : connectionCallbacks) {
callback.onConnected(connectionHint);
}
}
@Override
public void onConnectionSuspended(int cause) {
Log.d(TAG, "ConnectionCallbacks : onConnectionSuspended()");
for (ConnectionCallbacks callback : connectionCallbacks) {
callback.onConnectionSuspended(cause);
}
}
};
private final OnConnectionFailedListener baseConnectionFailedListener = new
OnConnectionFailedListener() {
@Override
public void onConnectionFailed(ConnectionResult result) {
Log.d(TAG, "OnConnectionFailedListener : onConnectionFailed()");
for (OnConnectionFailedListener listener : connectionFailedListeners) {
listener.onConnectionFailed(result);
}
}
};
private int usageCounter = 0;
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
private boolean shouldDisconnect = false;
public GoogleApiClientImpl(Context context, Looper looper, ApiClientSettings clientSettings,
@ -44,6 +90,10 @@ public class GoogleApiClientImpl implements GoogleApiClient {
this.connectionCallbacks.addAll(connectionCallbacks);
this.connectionFailedListeners.addAll(connectionFailedListeners);
if (this.clientSettings.sessionId == null) {
this.clientSettings.sessionId = hashCode();
}
for (Api api : apis.keySet()) {
ConnectionCallbacks baseConnectionCallbacks = new ConnectionCallbacks() {
@Override
@ -72,6 +122,41 @@ public class GoogleApiClientImpl implements GoogleApiClient {
}
}
<<<<<<< HEAD
=======
public synchronized void incrementUsageCounter() {
usageCounter++;
}
public synchronized void decrementUsageCounter() {
usageCounter--;
if (shouldDisconnect) disconnect();
}
public Looper getLooper() {
return looper;
}
public Api.Client 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;
}
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
@Override
public synchronized void connect() {
Log.d(TAG, "connect()");
@ -83,7 +168,7 @@ public class GoogleApiClientImpl implements GoogleApiClient {
Log.d(TAG, "Already connected/connecting, nothing to do");
return;
}
for (ApiClient connection : apiConnections.values()) {
for (Api.Client connection : apiConnections.values()) {
if (!connection.isConnected()) {
connection.connect();
}
@ -92,17 +177,28 @@ public class GoogleApiClientImpl implements GoogleApiClient {
@Override
public synchronized void disconnect() {
<<<<<<< HEAD
Log.d(TAG, "disconnect()");
for (ApiClient connection : apiConnections.values()) {
if (connection.isConnected()) {
connection.disconnect();
=======
if (usageCounter > 0) {
shouldDisconnect = true;
} else {
Log.d(TAG, "disconnect()");
for (Api.Client connection : apiConnections.values()) {
if (connection.isConnected()) {
connection.disconnect();
}
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
}
}
}
@Override
public synchronized boolean isConnected() {
for (ApiClient connection : apiConnections.values()) {
for (Api.Client connection : apiConnections.values()) {
if (!connection.isConnected()) return false;
}
return true;
@ -110,7 +206,7 @@ public class GoogleApiClientImpl implements GoogleApiClient {
@Override
public synchronized boolean isConnecting() {
for (ApiClient connection : apiConnections.values()) {
for (Api.Client connection : apiConnections.values()) {
if (connection.isConnecting()) return true;
}
return false;

View file

@ -5,11 +5,33 @@
package org.microg.gms.common.api;
<<<<<<< HEAD
import android.annotation.SuppressLint;
=======
import android.content.Context;
import android.os.Bundle;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.GoogleApi;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.TaskCompletionSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
public class GoogleApiManager {
@SuppressLint("StaticFieldLeak")
private static GoogleApiManager instance;
<<<<<<< HEAD
=======
private Context context;
private Map<ApiInstance, Api.Client> clientMap = new HashMap<>();
private Map<ApiInstance, List<WaitingApiCall<?>>> waitingApiCallMap = new HashMap<>();
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
private GoogleApiManager() {
}
@ -18,4 +40,159 @@ public class GoogleApiManager {
if (instance == null) instance = new GoogleApiManager();
}
<<<<<<< HEAD
=======
private synchronized <O extends Api.ApiOptions, A extends Api.Client> A clientForApi(GoogleApi<O> api) {
ApiInstance apiInstance = new ApiInstance(api);
if (clientMap.containsKey(apiInstance)) {
return (A) clientMap.get(apiInstance);
} else {
Api.Client client = api.api.getBuilder().build(api.getOptions(), context, context.getMainLooper(), null, new ConnectionCallback(apiInstance), new ConnectionFailedListener(apiInstance));
clientMap.put(apiInstance, client);
waitingApiCallMap.put(apiInstance, new ArrayList<>());
return (A) client;
}
}
public synchronized <O extends Api.ApiOptions, R, A extends Api.Client> void scheduleTask(GoogleApi<O> api, PendingGoogleApiCall<R, A> apiCall, TaskCompletionSource<R> completionSource) {
A client = clientForApi(api);
boolean connecting = client.isConnecting();
boolean connected = client.isConnected();
if (connected) {
try {
apiCall.execute(client, completionSource);
} catch (Exception e) {
completionSource.setException(e);
}
} else {
waitingApiCallMap.get(new ApiInstance(api)).add(new WaitingApiCall<R>((PendingGoogleApiCall<R, Api.Client>) apiCall, completionSource));
if (!connecting) {
client.connect();
}
}
}
private synchronized void onInstanceConnected(ApiInstance apiInstance, Bundle connectionHint) {
List<WaitingApiCall<?>> waitingApiCalls = waitingApiCallMap.get(apiInstance);
for (WaitingApiCall<?> waitingApiCall : waitingApiCalls) {
try {
waitingApiCall.execute(clientMap.get(apiInstance));
} catch (Exception e) {
waitingApiCall.failed(e);
}
}
waitingApiCalls.clear();
}
private synchronized void onInstanceSuspended(ApiInstance apiInstance, int cause) {
}
private synchronized void onInstanceFailed(ApiInstance apiInstance, ConnectionResult result) {
List<WaitingApiCall<?>> waitingApiCalls = waitingApiCallMap.get(apiInstance);
for (WaitingApiCall<?> waitingApiCall : waitingApiCalls) {
waitingApiCall.failed(new RuntimeException(result.getErrorMessage()));
}
waitingApiCalls.clear();
}
private class ConnectionCallback implements ConnectionCallbacks {
private ApiInstance apiInstance;
public ConnectionCallback(ApiInstance apiInstance) {
this.apiInstance = apiInstance;
}
@Override
public void onConnected(Bundle connectionHint) {
onInstanceConnected(apiInstance, connectionHint);
}
@Override
public void onConnectionSuspended(int cause) {
onInstanceSuspended(apiInstance, cause);
}
}
private class ConnectionFailedListener implements OnConnectionFailedListener {
private ApiInstance apiInstance;
public ConnectionFailedListener(ApiInstance apiInstance) {
this.apiInstance = apiInstance;
}
@Override
public void onConnectionFailed(ConnectionResult result) {
onInstanceFailed(apiInstance, result);
}
}
private static class WaitingApiCall<R> {
private PendingGoogleApiCall<R, Api.Client> apiCall;
private TaskCompletionSource<R> completionSource;
public WaitingApiCall(PendingGoogleApiCall<R, Api.Client> apiCall, TaskCompletionSource<R> completionSource) {
this.apiCall = apiCall;
this.completionSource = completionSource;
}
public void execute(Api.Client client) throws Exception {
apiCall.execute(client, completionSource);
}
public void failed(Exception e) {
completionSource.setException(e);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WaitingApiCall<?> that = (WaitingApiCall<?>) o;
if (apiCall != null ? !apiCall.equals(that.apiCall) : that.apiCall != null) return false;
return completionSource != null ? completionSource.equals(that.completionSource) : that.completionSource == null;
}
@Override
public int hashCode() {
int result = apiCall != null ? apiCall.hashCode() : 0;
result = 31 * result + (completionSource != null ? completionSource.hashCode() : 0);
return result;
}
}
private static class ApiInstance {
private Class<?> apiClass;
private Api.ApiOptions apiOptions;
public ApiInstance(Class<?> apiClass, Api.ApiOptions apiOptions) {
this.apiClass = apiClass;
this.apiOptions = apiOptions;
}
public ApiInstance(GoogleApi<?> api) {
this(api.getClass(), api.getOptions());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ApiInstance that = (ApiInstance) o;
if (apiClass != null ? !apiClass.equals(that.apiClass) : that.apiClass != null) return false;
return apiOptions != null ? apiOptions.equals(that.apiOptions) : that.apiOptions == null;
}
@Override
public int hashCode() {
int result = apiClass != null ? apiClass.hashCode() : 0;
result = 31 * result + (apiOptions != null ? apiOptions.hashCode() : 0);
return result;
}
}
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
}

View file

@ -0,0 +1,13 @@
/*
* SPDX-FileCopyrightText: 2020, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.common.api;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.tasks.TaskCompletionSource;
public interface PendingGoogleApiCall<R, A extends Api.Client> {
void execute(A client, TaskCompletionSource<R> completionSource) throws Exception;
}

View file

@ -47,6 +47,20 @@ class ResultCallbackHandler<R extends Result> extends Handler {
}
}
<<<<<<< HEAD
=======
public void sendResultCallback(ResultCallback<R> callback, R result) {
Message message = new Message();
message.what = CALLBACK_ON_COMPLETE;
message.obj = new OnCompleteObject<R>(callback, result);
sendMessage(message);
}
public void sendTimeoutResultCallback(AbstractPendingResult pendingResult, long millis) {
}
>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
public static class OnCompleteObject<R extends Result> {
public ResultCallback<R> callback;
public R result;

View file

@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2020, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.common.api;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.tasks.TaskCompletionSource;
public interface ReturningGoogleApiCall<R, A extends Api.Client> extends PendingGoogleApiCall<R, A> {
R execute(A client) throws Exception;
@Override
default void execute(A client, TaskCompletionSource<R> completionSource) {
try {
completionSource.setResult(execute(client));
} catch (Exception e) {
completionSource.setException(e);
}
}
}

Some files were not shown because too many files have changed in this diff Show more