Restructure modules 18c3a6154d
This commit is contained in:
parent
5f278780e1
commit
b19fad1281
35 changed files with 2204 additions and 21 deletions
19
build.gradle
19
build.gradle
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in a new issue