diff --git a/build.gradle b/build.gradle
index 2c713c7c..3a471c38 100644
--- a/build.gradle
+++ b/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)
diff --git a/play-services-base/src/main/java/com/google/android/gms/common/GoogleApiAvailability.java b/play-services-base/src/main/java/com/google/android/gms/common/GoogleApiAvailability.java
index 61ee1ec0..50ff0e23 100644
--- a/play-services-base/src/main/java/com/google/android/gms/common/GoogleApiAvailability.java
+++ b/play-services-base/src/main/java/com/google/android/gms/common/GoogleApiAvailability.java
@@ -50,4 +50,196 @@ public class GoogleApiAvailability {
return null;
}
+<<<<<<< HEAD
+=======
+ /**
+ * Returns a PendingIntent to address the provided connection failure.
+ *
+ * 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 minApkVersion.
+ *
+ * @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.
+ *
+ * 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.
+ *
+ * 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}.
+ *
+ * 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 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.
+ *
+ * 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)
}
diff --git a/play-services-base/src/main/java/com/google/android/gms/common/api/AccountInfo.java b/play-services-base/src/main/java/com/google/android/gms/common/api/AccountInfo.java
index fd400c45..30d6a169 100644
--- a/play-services-base/src/main/java/com/google/android/gms/common/api/AccountInfo.java
+++ b/play-services-base/src/main/java/com/google/android/gms/common/api/AccountInfo.java
@@ -20,5 +20,5 @@ import org.microg.safeparcel.AutoSafeParcelable;
@Deprecated
public class AccountInfo extends AutoSafeParcelable {
- public static final Creator CREATOR = new AutoCreator<>(AccountInfo.class);
+ public static final Creator CREATOR = new AutoCreator(AccountInfo.class);
}
diff --git a/play-services-base/src/main/java/com/google/android/gms/common/api/Api.java b/play-services-base/src/main/java/com/google/android/gms/common/api/Api.java
index 6b7f15e3..a6942637 100644
--- a/play-services-base/src/main/java/com/google/android/gms/common/api/Api.java
+++ b/play-services-base/src/main/java/com/google/android/gms/common/api/Api.java
@@ -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 {
}
+ @Hide
+ public interface Client {
+ void connect();
+
+ void disconnect();
+
+ boolean isConnected();
+
+ boolean isConnecting();
+ }
}
diff --git a/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApi.java b/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApi.java
index f0adb967..ff165974 100644
--- a/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApi.java
+++ b/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApi.java
@@ -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 implements HasApiKey {
@PublicApi(exclude = true)
+=======
+public abstract class GoogleApi implements HasApiKey {
+ private GoogleApiManager manager;
+ @Hide
+>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
public Api api;
+ @Hide
+ public O options;
@PublicApi(exclude = true)
protected GoogleApi(Context context, Api api) {
this.api = api;
+<<<<<<< HEAD
GoogleApiManager.getInstance();
+=======
+ this.manager = GoogleApiManager.getInstance(context);
+ }
+
+ @PublicApi(exclude = true)
+ protected GoogleApi(Context context, Api api, O options) {
+ this.api = api;
+ this.manager = GoogleApiManager.getInstance(context);
+ this.options = options;
+ }
+
+ @PublicApi(exclude = true)
+ protected Task scheduleTask(PendingGoogleApiCall apiCall) {
+ TaskCompletionSource completionSource = new TaskCompletionSource<>();
+ manager.scheduleTask(this, apiCall, completionSource);
+ return completionSource.getTask();
+ }
+
+ @Override
+ @PublicApi(exclude = true)
+ public ApiKey getApiKey() {
+ return null;
+>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
}
@PublicApi(exclude = true)
public O getOptions() {
- return null;
+ return options;
}
}
diff --git a/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApiActivity.java b/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApiActivity.java
index 8a6b0690..e5524cb9 100644
--- a/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApiActivity.java
+++ b/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApiActivity.java
@@ -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)
}
diff --git a/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApiClient.java b/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApiClient.java
index 0e20b6d5..a841fd98 100644
--- a/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApiClient.java
+++ b/play-services-base/src/main/java/com/google/android/gms/common/api/GoogleApiClient.java
@@ -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 apis = new HashMap<>();
private final Set connectionCallbacks = new HashSet<>();
private final Set connectionFailedListeners = new HashSet<>();
private final Looper looper;
+=======
+ private final Map apis = new HashMap();
+ private final Set connectionCallbacks = new HashSet();
+ private final Set connectionFailedListeners = new HashSet();
+ private final Set scopes = new HashSet();
+ private String accountName;
+ private int clientId = -1;
+ private FragmentActivity fragmentActivity;
+ private Looper looper;
+ private int gravityForPopups;
+ private OnConnectionFailedListener unresolvedConnectionFailedListener;
+ private View viewForPopups;
+>>>>>>> 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
diff --git a/play-services-base/src/main/java/com/google/android/gms/common/api/PendingResult.java b/play-services-base/src/main/java/com/google/android/gms/common/api/PendingResult.java
index e5f92160..1e5c462f 100644
--- a/play-services-base/src/main/java/com/google/android/gms/common/api/PendingResult.java
+++ b/play-services-base/src/main/java/com/google/android/gms/common/api/PendingResult.java
@@ -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.
+ *
+ *
+ * - via blocking calls to {@link #await()}, or {@link #await(long, TimeUnit)}, or
+ * - via a callback by passing in an object implementing interface {@link ResultCallback} to
+ * {@link #setResultCallback(ResultCallback)}.
+ *
+ * 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.
+ *
+ * TODO: Docs
+ */
+public interface PendingResult {
+ /**
+ * 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 callback, long time, TimeUnit unit);
+
+ public void setResultCallback(ResultCallback callback);
+>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClient.java b/play-services-base/src/main/java/org/microg/gms/common/DummyApiClient.java
similarity index 56%
rename from play-services-base/src/main/java/org/microg/gms/common/api/ApiClient.java
rename to play-services-base/src/main/java/org/microg/gms/common/DummyApiClient.java
index 602e150e..c527866f 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClient.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/DummyApiClient.java
@@ -14,14 +14,30 @@
* limitations under the License.
*/
-package org.microg.gms.common.api;
+package org.microg.gms.common;
-public interface ApiClient {
- void connect();
+import com.google.android.gms.common.api.Api;
- void disconnect();
+public class DummyApiClient implements Api.Client {
+ private boolean connected = false;
- boolean isConnected();
+ @Override
+ public void connect() {
+ connected = true;
+ }
- boolean isConnecting();
+ @Override
+ public void disconnect() {
+ connected = false;
+ }
+
+ @Override
+ public boolean isConnected() {
+ return connected;
+ }
+
+ @Override
+ public boolean isConnecting() {
+ return false;
+ }
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/GmsClient.java b/play-services-base/src/main/java/org/microg/gms/common/GmsClient.java
new file mode 100644
index 00000000..e5b71717
--- /dev/null
+++ b/play-services-base/src/main/java/org/microg/gms/common/GmsClient.java
@@ -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 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);
+ }
+ }
+
+}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/GmsConnector.java b/play-services-base/src/main/java/org/microg/gms/common/GmsConnector.java
new file mode 100644
index 00000000..b77c6d2c
--- /dev/null
+++ b/play-services-base/src/main/java/org/microg/gms/common/GmsConnector.java
@@ -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 {
+ private static final String TAG = "GmsConnector";
+
+ private final GoogleApiClientImpl apiClient;
+ private final Api api;
+ private final Callback callback;
+
+ public GmsConnector(GoogleApiClient apiClient, Api api, Callback callback) {
+ this.apiClient = (GoogleApiClientImpl) apiClient;
+ this.api = api;
+ this.callback = callback;
+ }
+
+ public static PendingResult call(GoogleApiClient client, Api api, GmsConnector.Callback callback) {
+ return new GmsConnector(client, api, callback).connect();
+ }
+
+ public AbstractPendingResult connect() {
+ Log.d(TAG, "connect()");
+ apiClient.incrementUsageCounter();
+ apiClient.getApiConnection(api);
+ Looper looper = apiClient.getLooper();
+ final AbstractPendingResult result = new AbstractPendingResult(looper);
+ Message msg = new Message();
+ msg.obj = result;
+ new Handler(looper).sendMessage(msg);
+ return result;
+ }
+
+ public interface Callback {
+ void onClientAvailable(C client, ResultProvider resultProvider) throws RemoteException;
+
+ interface ResultProvider {
+ 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 result = (AbstractPendingResult) msg.obj;
+ try {
+ C connection = (C) apiClient.getApiConnection(api);
+ callback.onClientAvailable(connection, new GmsConnector.Callback.ResultProvider() {
+ @Override
+ public void onResultAvailable(R realResult) {
+ result.deliverResult(realResult);
+ apiClient.decrementUsageCounter();
+ }
+ });
+ } catch (RemoteException ignored) {
+
+ }
+ }
+ }
+}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/MultiConnectionKeeper.java b/play-services-base/src/main/java/org/microg/gms/common/MultiConnectionKeeper.java
new file mode 100644
index 00000000..30c1d61c
--- /dev/null
+++ b/play-services-base/src/main/java/org/microg/gms/common/MultiConnectionKeeper.java
@@ -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 connections = new HashMap();
+
+ 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 connectionForwards = new HashSet();
+ private boolean bound = false;
+ private boolean connected = false;
+ private IBinder binder;
+ private ComponentName component;
+ private ServiceConnection serviceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+ 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();
+ }
+ }
+}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/AbstractPendingResult.java b/play-services-base/src/main/java/org/microg/gms/common/api/AbstractPendingResult.java
index cea4229b..df6b96e3 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/AbstractPendingResult.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/AbstractPendingResult.java
@@ -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(looper);
+>>>>>>> 49892e88 (Restructure modules https://github.com/microg/GmsCore/commit/18c3a6154dc41cebe1d4aeda5592b8f23928356f)
}
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientBuilder.java b/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientBuilder.java
index b5aa386f..18336fa5 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientBuilder.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientBuilder.java
@@ -22,5 +22,5 @@ import android.os.Looper;
import com.google.android.gms.common.api.Api;
public interface ApiClientBuilder {
- 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);
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientSettings.java b/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientSettings.java
index d1e314a7..af67e799 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientSettings.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/ApiClientSettings.java
@@ -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 scopes;
+ public int gravityForPopups;
+ public View viewForPopups;
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiClientImpl.java b/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiClientImpl.java
index 371a6555..2e023fde 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiClientImpl.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiClientImpl.java
@@ -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 apiConnections = new HashMap<>();
private final Set connectionCallbacks = new HashSet<>();
private final Set connectionFailedListeners = new HashSet<>();
+=======
+ private final Context context;
+ private final Looper looper;
+ private final ApiClientSettings clientSettings;
+ private final Map apis = new HashMap();
+ private final Map apiConnections = new HashMap();
+ private final Set connectionCallbacks = new HashSet();
+ private final Set connectionFailedListeners = new HashSet();
+ 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 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;
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiManager.java b/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiManager.java
index a5fa2545..d30293ed 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiManager.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/GoogleApiManager.java
@@ -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 clientMap = new HashMap<>();
+ private Map>> 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 A clientForApi(GoogleApi 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 void scheduleTask(GoogleApi api, PendingGoogleApiCall apiCall, TaskCompletionSource 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((PendingGoogleApiCall) apiCall, completionSource));
+ if (!connecting) {
+ client.connect();
+ }
+ }
+ }
+
+ private synchronized void onInstanceConnected(ApiInstance apiInstance, Bundle connectionHint) {
+ List> 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> 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 {
+ private PendingGoogleApiCall apiCall;
+ private TaskCompletionSource completionSource;
+
+ public WaitingApiCall(PendingGoogleApiCall apiCall, TaskCompletionSource 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)
}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/PendingGoogleApiCall.java b/play-services-base/src/main/java/org/microg/gms/common/api/PendingGoogleApiCall.java
new file mode 100644
index 00000000..578d02b9
--- /dev/null
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/PendingGoogleApiCall.java
@@ -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 {
+ void execute(A client, TaskCompletionSource completionSource) throws Exception;
+}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/ResultCallbackHandler.java b/play-services-base/src/main/java/org/microg/gms/common/api/ResultCallbackHandler.java
index a737a076..3401f596 100644
--- a/play-services-base/src/main/java/org/microg/gms/common/api/ResultCallbackHandler.java
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/ResultCallbackHandler.java
@@ -47,6 +47,20 @@ class ResultCallbackHandler extends Handler {
}
}
+<<<<<<< HEAD
+=======
+ public void sendResultCallback(ResultCallback callback, R result) {
+ Message message = new Message();
+ message.what = CALLBACK_ON_COMPLETE;
+ message.obj = new OnCompleteObject(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 {
public ResultCallback callback;
public R result;
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/ReturningGoogleApiCall.java b/play-services-base/src/main/java/org/microg/gms/common/api/ReturningGoogleApiCall.java
new file mode 100644
index 00000000..f836b9d4
--- /dev/null
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/ReturningGoogleApiCall.java
@@ -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 extends PendingGoogleApiCall {
+ R execute(A client) throws Exception;
+
+ @Override
+ default void execute(A client, TaskCompletionSource completionSource) {
+ try {
+ completionSource.setResult(execute(client));
+ } catch (Exception e) {
+ completionSource.setException(e);
+ }
+ }
+}
diff --git a/play-services-base/src/main/java/org/microg/gms/common/api/VoidReturningGoogleApiCall.java b/play-services-base/src/main/java/org/microg/gms/common/api/VoidReturningGoogleApiCall.java
new file mode 100644
index 00000000..ee8cbf66
--- /dev/null
+++ b/play-services-base/src/main/java/org/microg/gms/common/api/VoidReturningGoogleApiCall.java
@@ -0,0 +1,23 @@
+/*
+ * SPDX-FileCopyrightText: 2022 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 VoidReturningGoogleApiCall extends PendingGoogleApiCall{
+ void execute(A client) throws Exception;
+
+ @Override
+ default void execute(A client, TaskCompletionSource completionSource) {
+ try {
+ execute(client);
+ completionSource.setResult(null);
+ } catch (Exception e) {
+ completionSource.setException(e);
+ }
+ }
+}
diff --git a/play-services-basement/build.gradle b/play-services-basement/build.gradle
index 8971fb98..bbc86b99 100644
--- a/play-services-basement/build.gradle
+++ b/play-services-basement/build.gradle
@@ -18,7 +18,7 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
dependencies {
- api "org.microg:safe-parcel:1.7.0"
+ api "org.microg:safe-parcel:$safeParcelVersion"
// Dependencies from play-services-basement:18.0.0
api "androidx.collection:collection:$collectionVersion"
diff --git a/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ConnectionInfo.aidl b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ConnectionInfo.aidl
new file mode 100644
index 00000000..b393f11d
--- /dev/null
+++ b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/ConnectionInfo.aidl
@@ -0,0 +1,7 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal;
+parcelable ConnectionInfo;
diff --git a/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGmsCallbacks.aidl b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGmsCallbacks.aidl
index b0210281..8fe63347 100644
--- a/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGmsCallbacks.aidl
+++ b/play-services-basement/src/main/aidl/com/google/android/gms/common/internal/IGmsCallbacks.aidl
@@ -1,7 +1,15 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
package com.google.android.gms.common.internal;
import android.os.Bundle;
+import com.google.android.gms.common.internal.ConnectionInfo;
interface IGmsCallbacks {
void onPostInitComplete(int statusCode, IBinder binder, in Bundle params);
+ void onAccountValidationComplete(int statusCode, in Bundle params);
+ void onPostInitCompleteWithConnectionInfo(int statusCode, IBinder binder, in ConnectionInfo info);
}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/ConnectionInfo.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/ConnectionInfo.java
new file mode 100644
index 00000000..19326d08
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/ConnectionInfo.java
@@ -0,0 +1,31 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import androidx.annotation.NonNull;
+import com.google.android.gms.common.Feature;
+import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
+
+@SafeParcelable.Class
+public class ConnectionInfo extends AbstractSafeParcelable {
+ @Field(1)
+ public Bundle params;
+ @Field(2)
+ public Feature[] features;
+ @Field(3)
+ public int unknown3;
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ CREATOR.writeToParcel(this, dest, flags);
+ }
+
+ public static final SafeParcelableCreatorAndWriter CREATOR = findCreator(ConnectionInfo.class);
+}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/ValidateAccountRequest.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/ValidateAccountRequest.java
index 75e59d95..1cf0ecc1 100644
--- a/play-services-basement/src/main/java/com/google/android/gms/common/internal/ValidateAccountRequest.java
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/ValidateAccountRequest.java
@@ -16,8 +16,18 @@
package com.google.android.gms.common.internal;
-import org.microg.safeparcel.AutoSafeParcelable;
+import android.os.Parcel;
+import androidx.annotation.NonNull;
+import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
+import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
-public class ValidateAccountRequest extends AutoSafeParcelable {
- public static Creator CREATOR = new AutoCreator<>(ValidateAccountRequest.class);
+@SafeParcelable.Class
+public class ValidateAccountRequest extends AbstractSafeParcelable {
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ CREATOR.writeToParcel(this, dest, flags);
+ }
+
+ public static SafeParcelableCreatorAndWriter CREATOR = findCreator(ValidateAccountRequest.class);
}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/AbstractSafeParcelable.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/AbstractSafeParcelable.java
new file mode 100644
index 00000000..ec7d84d5
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/AbstractSafeParcelable.java
@@ -0,0 +1,24 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+public abstract class AbstractSafeParcelable implements SafeParcelable {
+
+ @SuppressWarnings("unchecked")
+ public static SafeParcelableCreatorAndWriter findCreator(java.lang.Class tClass) {
+ String creatorClassName = tClass.getName() + "$000Creator";
+ try {
+ return (SafeParcelableCreatorAndWriter) java.lang.Class.forName(creatorClassName).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("No Creator found for " + tClass.getName(), e);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelReader.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelReader.java
new file mode 100644
index 00000000..226f50e8
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelReader.java
@@ -0,0 +1,328 @@
+/*
+ * SPDX-FileCopyrightText: 2015, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+@SuppressWarnings("MagicNumber")
+public final class SafeParcelReader {
+
+ private SafeParcelReader() {
+ }
+
+ @Deprecated
+ public static int halfOf(int i) {
+ return i & 0xFFFF;
+ }
+
+ public static int getFieldId(int header) {
+ return header & 0xFFFF;
+ }
+
+ @Deprecated
+ public static int readSingleInt(Parcel parcel) {
+ return parcel.readInt();
+ }
+
+ public static int readHeader(Parcel parcel) {
+ return parcel.readInt();
+ }
+
+ private static int readSize(Parcel parcel, int header) {
+ if ((header & 0xFFFF0000) != 0xFFFF0000)
+ return header >> 16 & 0xFFFF;
+ return parcel.readInt();
+ }
+
+ private static void readExpectedSize(Parcel parcel, int header, int expectedSize) {
+ int i = readSize(parcel, header);
+ if (i != expectedSize)
+ throw new ReadException("Expected size " + expectedSize + " got " + i + " (0x" + Integer.toHexString(i) + ")", parcel);
+ }
+
+ @Deprecated
+ public static int readStart(Parcel parcel) {
+ return readObjectHeader(parcel);
+ }
+
+ public static int readObjectHeader(Parcel parcel) {
+ int header = readHeader(parcel);
+ int size = readSize(parcel, header);
+ int start = parcel.dataPosition();
+ if (getFieldId(header) != SafeParcelable.SAFE_PARCEL_OBJECT_MAGIC)
+ throw new ReadException("Expected object header. Got 0x" + Integer.toHexString(header), parcel);
+ int end = start + size;
+ if ((end < start) || (end > parcel.dataSize()))
+ throw new ReadException("Size read is invalid start=" + start + " end=" + end, parcel);
+ return end;
+ }
+
+ public static int readInt(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 4);
+ return parcel.readInt();
+ }
+
+ public static byte readByte(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 4);
+ return (byte) parcel.readInt();
+ }
+
+ public static short readShort(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 4);
+ return (short) parcel.readInt();
+ }
+
+ public static boolean readBool(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 4);
+ return parcel.readInt() != 0;
+ }
+
+ public static long readLong(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 8);
+ return parcel.readLong();
+ }
+
+ public static float readFloat(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 4);
+ return parcel.readFloat();
+ }
+
+ public static double readDouble(Parcel parcel, int header) {
+ readExpectedSize(parcel, header, 8);
+ return parcel.readDouble();
+ }
+
+ public static String readString(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ String string = parcel.readString();
+ parcel.setDataPosition(start + size);
+ return string;
+ }
+
+ public static IBinder readBinder(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ IBinder binder = parcel.readStrongBinder();
+ parcel.setDataPosition(start + size);
+ return binder;
+ }
+
+ public static T readParcelable(Parcel parcel, int header, Parcelable.Creator creator) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ T t = creator.createFromParcel(parcel);
+ parcel.setDataPosition(start + size);
+ return t;
+ }
+
+ public static ArrayList readList(Parcel parcel, int header, ClassLoader classLoader) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ ArrayList list = parcel.readArrayList(classLoader);
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static HashMap readMap(Parcel parcel, int header, ClassLoader classLoader) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ HashMap map = parcel.readHashMap(classLoader);
+ parcel.setDataPosition(start + size);
+ return map;
+ }
+
+ public static ArrayList readParcelableList(Parcel parcel, int header, Parcelable.Creator creator) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ ArrayList list = parcel.createTypedArrayList(creator);
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readStringList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ ArrayList list = parcel.createStringArrayList();
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readIntegerList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ ArrayList list = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ list.add(parcel.readInt());
+ }
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readLongList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ ArrayList list = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ list.add(parcel.readLong());
+ }
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readFloatList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ ArrayList list = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ list.add(parcel.readFloat());
+ }
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readDoubleList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ ArrayList list = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ list.add(parcel.readDouble());
+ }
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static ArrayList readBooleanList(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ ArrayList list = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
+ list.add(parcel.readInt() != 0);
+ }
+ parcel.setDataPosition(start + size);
+ return list;
+ }
+
+ public static T[] readParcelableArray(Parcel parcel, int header, Parcelable.Creator creator) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ T[] arr = parcel.createTypedArray(creator);
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static String[] readStringArray(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ String[] arr = parcel.createStringArray();
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static byte[] readByteArray(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ byte[] arr = parcel.createByteArray();
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static byte[][] readByteArrayArray(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int length = parcel.readInt();
+ byte[][] arr = new byte[length][];
+ for (int i = 0; i < length; i++) {
+ arr[i] = parcel.createByteArray();
+ }
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static float[] readFloatArray(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ float[] arr = parcel.createFloatArray();
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static int[] readIntArray(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ int[] arr = parcel.createIntArray();
+ parcel.setDataPosition(start + size);
+ return arr;
+ }
+
+ public static Bundle readBundle(Parcel parcel, int header, ClassLoader classLoader) {
+ int size = readSize(parcel, header);
+ if (size == 0)
+ return null;
+ int start = parcel.dataPosition();
+ Bundle bundle = parcel.readBundle(classLoader);
+ parcel.setDataPosition(start + size);
+ return bundle;
+ }
+
+ public static void skip(Parcel parcel, int header) {
+ int size = readSize(parcel, header);
+ parcel.setDataPosition(parcel.dataPosition() + size);
+ }
+
+ public static class ReadException extends RuntimeException {
+ public ReadException(String message, Parcel parcel) {
+ super(message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelWriter.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelWriter.java
new file mode 100644
index 00000000..b2f96116
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelWriter.java
@@ -0,0 +1,384 @@
+/*
+ * SPDX-FileCopyrightText: 2015, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+import java.util.Map;
+
+@SuppressWarnings("MagicNumber")
+public final class SafeParcelWriter {
+
+ private SafeParcelWriter() {
+ }
+
+ private static void writeHeader(Parcel parcel, int fieldId, int size) {
+ if (size >= 0xFFFF) {
+ parcel.writeInt(0xFFFF0000 | fieldId);
+ parcel.writeInt(size);
+ } else {
+ parcel.writeInt(size << 16 | fieldId);
+ }
+ }
+
+ @Deprecated
+ public static int writeStart(Parcel parcel) {
+ return writeObjectHeader(parcel);
+ }
+
+ public static int writeObjectHeader(Parcel parcel) {
+ writeHeader(parcel, SafeParcelable.SAFE_PARCEL_OBJECT_MAGIC, 0xFFFF);
+ return parcel.dataPosition();
+ }
+
+ private static int writeObjectHeader(Parcel parcel, int fieldId) {
+ writeHeader(parcel, fieldId, 0xFFFF);
+ return parcel.dataPosition();
+ }
+
+ @Deprecated
+ public static void writeEnd(Parcel parcel, int start) {
+ finishObjectHeader(parcel, start);
+ }
+
+ public static void finishObjectHeader(Parcel parcel, int start) {
+ int end = parcel.dataPosition();
+ int length = end - start;
+ parcel.setDataPosition(start - 4);
+ parcel.writeInt(length);
+ parcel.setDataPosition(end);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Boolean val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 4);
+ parcel.writeInt(val ? 1 : 0);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Byte val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 4);
+ parcel.writeInt(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Short val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 4);
+ parcel.writeInt(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Integer val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 4);
+ parcel.writeInt(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Long val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 8);
+ parcel.writeLong(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Float val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 4);
+ parcel.writeFloat(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, Double val) {
+ if (val == null) return;
+ writeHeader(parcel, fieldId, 8);
+ parcel.writeDouble(val);
+ }
+
+ public static void write(Parcel parcel, int fieldId, String val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeString(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, Parcelable val, int flags, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ val.writeToParcel(parcel, flags);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, Bundle val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeBundle(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, byte[] val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeByteArray(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, byte[][] val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.length);
+ for (byte[] arr : val) {
+ parcel.writeByteArray(arr);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, float[] val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeFloatArray(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, int[] val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeIntArray(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, String[] val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeStringArray(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeStringList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeStringList(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeIntegerList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (Integer i : val) {
+ parcel.writeInt(i);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeLongList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (Long l : val) {
+ parcel.writeLong(l);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeFloatList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (Float f : val) {
+ parcel.writeFloat(f);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeDoubleList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (Double d : val) {
+ parcel.writeDouble(d);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void writeBooleanList(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (Boolean b : val) {
+ parcel.writeInt(b ? 1 : 0);
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ private static void writeArrayPart(Parcel parcel, T val, int flags) {
+ int before = parcel.dataPosition();
+ parcel.writeInt(1);
+ int start = parcel.dataPosition();
+ val.writeToParcel(parcel, flags);
+ int end = parcel.dataPosition();
+ parcel.setDataPosition(before);
+ parcel.writeInt(end - start);
+ parcel.setDataPosition(end);
+ }
+
+ public static void write(Parcel parcel, int fieldId, T[] val, int flags, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.length);
+ for (T t : val) {
+ if (t == null) {
+ parcel.writeInt(0);
+ } else {
+ writeArrayPart(parcel, t, flags);
+ }
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, List val, int flags, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeInt(val.size());
+ for (T t : val) {
+ if (t == null) {
+ parcel.writeInt(0);
+ } else {
+ writeArrayPart(parcel, t, flags);
+ }
+ }
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, Parcel val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.appendFrom(val, 0, val.dataSize());
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, List val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeList(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, Map val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeMap(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+ public static void write(Parcel parcel, int fieldId, IBinder val, boolean mayNull) {
+ if (val == null) {
+ if (mayNull) {
+ writeHeader(parcel, fieldId, 0);
+ }
+ } else {
+ int start = writeObjectHeader(parcel, fieldId);
+ parcel.writeStrongBinder(val);
+ finishObjectHeader(parcel, start);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelable.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelable.java
new file mode 100644
index 00000000..0d8d1cc0
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelable.java
@@ -0,0 +1,55 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+import android.os.Parcelable;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+public interface SafeParcelable extends Parcelable {
+ int SAFE_PARCEL_OBJECT_MAGIC = 0x4F45;
+
+ @Target(ElementType.TYPE)
+ @interface Class {
+ }
+
+ @Target(ElementType.CONSTRUCTOR)
+ @interface Constructor {
+
+ }
+
+ @Target(ElementType.PARAMETER)
+ @interface Param {
+ int value();
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.FIELD)
+ @interface Field {
+ int value();
+
+ boolean mayNull() default false;
+
+ java.lang.Class> subClass() default SafeParcelable.class;
+
+ boolean useValueParcel() default false;
+
+ boolean useDirectList() default false;
+
+ long versionCode() default -1;
+
+ String defaultValue() default "";
+
+ String type() default "";
+
+ String getterName() default "";
+
+ String getter() default "";
+ }
+}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableCreatorAndWriter.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableCreatorAndWriter.java
new file mode 100644
index 00000000..6afaa9c6
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableCreatorAndWriter.java
@@ -0,0 +1,13 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public interface SafeParcelableCreatorAndWriter extends Parcelable.Creator {
+ void writeToParcel(T object, Parcel parcel, int flags);
+}
diff --git a/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableSerializer.java b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableSerializer.java
new file mode 100644
index 00000000..66b8b4d5
--- /dev/null
+++ b/play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelableSerializer.java
@@ -0,0 +1,30 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.common.internal.safeparcel;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class SafeParcelableSerializer {
+ public static T deserializeFromBytes(byte[] bytes, Parcelable.Creator tCreator) {
+ if (bytes == null) return null;
+ Parcel parcel = Parcel.obtain();
+ parcel.unmarshall(bytes, 0, bytes.length);
+ parcel.setDataPosition(0);
+ T parcelable = tCreator.createFromParcel(parcel);
+ parcel.recycle();
+ return parcelable;
+ }
+
+ public static byte[] serializeToBytes(T parcelable) {
+ if (parcelable == null) return null;
+ Parcel parcel = Parcel.obtain();
+ parcelable.writeToParcel(parcel, 0);
+ byte[] bytes = parcel.marshall();
+ parcel.recycle();
+ return bytes;
+ }
+}
diff --git a/play-services-basement/src/main/java/org/microg/gms/common/Hide.java b/play-services-basement/src/main/java/org/microg/gms/common/Hide.java
new file mode 100644
index 00000000..e15414b5
--- /dev/null
+++ b/play-services-basement/src/main/java/org/microg/gms/common/Hide.java
@@ -0,0 +1,19 @@
+/*
+ * SPDX-FileCopyrightText: 2023 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.common;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Hide the class, method or field from the public API.
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface Hide {
+}
diff --git a/play-services-basement/src/main/java/org/microg/gms/common/PublicApi.java b/play-services-basement/src/main/java/org/microg/gms/common/PublicApi.java
index 92663979..a7fb9b44 100644
--- a/play-services-basement/src/main/java/org/microg/gms/common/PublicApi.java
+++ b/play-services-basement/src/main/java/org/microg/gms/common/PublicApi.java
@@ -43,6 +43,8 @@ public @interface PublicApi {
* marked as public api.
*
* @return true if the method or field is not part of the public api
+ * @deprecated use {@link Hide} instead
*/
+ @Deprecated
boolean exclude() default false;
}
diff --git a/play-services-core/src/main/java/org/microg/gms/auth/login/AssistantActivity.java b/play-services-core/src/main/java/org/microg/gms/auth/login/AssistantActivity.java
index d53f38dd..b4bea3f8 100644
--- a/play-services-core/src/main/java/org/microg/gms/auth/login/AssistantActivity.java
+++ b/play-services-core/src/main/java/org/microg/gms/auth/login/AssistantActivity.java
@@ -17,6 +17,7 @@
package org.microg.gms.auth.login;
import android.annotation.SuppressLint;
+import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.DisplayMetrics;
@@ -25,11 +26,10 @@ import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.StringRes;
-import androidx.appcompat.app.AppCompatActivity;
import com.mgoogle.android.gms.R;
-public abstract class AssistantActivity extends AppCompatActivity {
+public abstract class AssistantActivity extends Activity {
private static final int TITLE_MIN_HEIGHT = 64;
private static final double TITLE_WIDTH_FACTOR = (8.0 / 18.0);