mirror of
https://github.com/TeamVanced/VancedMicroG
synced 2025-01-14 13:17:31 +01:00
Update lib for API changes, add support for wearable listening and sending messages
This commit is contained in:
parent
25d0e3be42
commit
29d8b8fbb5
@ -18,4 +18,7 @@
|
||||
|
||||
subprojects {
|
||||
group = 'org.microg'
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
2
extern/GmsApi
vendored
2
extern/GmsApi
vendored
@ -1 +1 @@
|
||||
Subproject commit be6af2eeb76ba4bcc1700285f2ba87f217ab6ac2
|
||||
Subproject commit b9cb95d39bdb4bbac6dd0d2b0405e4d5a23717c2
|
@ -48,7 +48,6 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-v4:23.4.0'
|
||||
compile project(':play-services-common-api')
|
||||
compile project(':play-services-basement')
|
||||
compile project(':play-services-tasks')
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest package="com.google.android.gms"
|
||||
<manifest package="org.microg.gms.base"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-sdk android:minSdkVersion="9"/>
|
||||
|
@ -1,310 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2015 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 com.google.android.gms.common;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Contains all possible error codes for when a client fails to connect to Google Play services.
|
||||
* These error codes are used by {@link GoogleApiClient.OnConnectionFailedListener}.
|
||||
*/
|
||||
public class ConnectionResult {
|
||||
/**
|
||||
* The connection was successful.
|
||||
*/
|
||||
public static final int SUCCESS = 0;
|
||||
/**
|
||||
* Google Play services is missing on this device. The calling activity should pass this error
|
||||
* code to {@link GooglePlayServicesUtil#getErrorDialog(int, Activity, int)} to get a localized
|
||||
* error dialog that will resolve the error when shown.
|
||||
*/
|
||||
public static final int SERVICE_MISSING = 1;
|
||||
/**
|
||||
* The installed version of Google Play services is out of date. The calling activity should
|
||||
* pass this error code to {@link GooglePlayServicesUtil#getErrorDialog(int, Activity, int)} to
|
||||
* get a localized error dialog that will resolve the error when shown.
|
||||
*/
|
||||
public static final int SERVICE_VERSION_UPDATE_REQUIRED = 2;
|
||||
/**
|
||||
* The installed version of Google Play services has been disabled on this device. The calling
|
||||
* activity should pass this error code to
|
||||
* {@link GooglePlayServicesUtil#getErrorDialog(int, Activity, int)} to get a localized error
|
||||
* dialog that will resolve the error when shown.
|
||||
*/
|
||||
public static final int SERVICE_DISABLED = 3;
|
||||
/**
|
||||
* The client attempted to connect to the service but the user is not signed in. The client may
|
||||
* choose to continue without using the API or it may call
|
||||
* {@link #startResolutionForResult(Activity, int)} to prompt the user to sign in. After the
|
||||
* sign in activity returns with {@link Activity#RESULT_OK} further attempts to connect should
|
||||
* succeed.
|
||||
*/
|
||||
public static final int SIGN_IN_REQUIRED = 4;
|
||||
/**
|
||||
* The client attempted to connect to the service with an invalid account name specified.
|
||||
*/
|
||||
public static final int INVALID_ACCOUNT = 5;
|
||||
/**
|
||||
* Completing the connection requires some form of resolution. A resolution will be available
|
||||
* to be started with {@link #startResolutionForResult(Activity, int)}. If the result returned
|
||||
* is {@link Activity#RESULT_OK}, then further attempts to connect should either complete or
|
||||
* continue on to the next issue that needs to be resolved.
|
||||
*/
|
||||
public static final int RESOLUTION_REQUIRED = 6;
|
||||
/**
|
||||
* A network error occurred. Retrying should resolve the problem.
|
||||
*/
|
||||
public static final int NETWORK_ERROR = 7;
|
||||
/**
|
||||
* An internal error occurred. Retrying should resolve the problem.
|
||||
*/
|
||||
public static final int INTERNAL_ERROR = 8;
|
||||
/**
|
||||
* The version of the Google Play services installed on this device is not authentic.
|
||||
*/
|
||||
public static final int SERVICE_INVALID = 9;
|
||||
/**
|
||||
* The application is misconfigured. This error is not recoverable and will be treated as
|
||||
* fatal. The developer should look at the logs after this to determine more actionable
|
||||
* information.
|
||||
*/
|
||||
public static final int DEVELOPER_ERROR = 10;
|
||||
/**
|
||||
* The application is not licensed to the user. This error is not recoverable and will be
|
||||
* treated as fatal.
|
||||
*/
|
||||
public static final int LICENSE_CHECK_FAILED = 11;
|
||||
/**
|
||||
* The client canceled the connection by calling {@link GoogleApiClient#disconnect()}.
|
||||
* Only returned by {@link GoogleApiClient#blockingConnect()}.
|
||||
*/
|
||||
public static final int CANCELED = 13;
|
||||
/**
|
||||
* The timeout was exceeded while waiting for the connection to complete. Only returned by
|
||||
* {@link GoogleApiClient#blockingConnect()}.
|
||||
*/
|
||||
public static final int TIMEOUT = 14;
|
||||
/**
|
||||
* An interrupt occurred while waiting for the connection complete. Only returned by
|
||||
* {@link GoogleApiClient#blockingConnect()}.
|
||||
*/
|
||||
public static final int INTERRUPTED = 15;
|
||||
/**
|
||||
* One of the API components you attempted to connect to is not available. The API will not
|
||||
* work on this device, and updating Google Play services will not likely solve the problem.
|
||||
* Using the API on the device should be avoided.
|
||||
*/
|
||||
public static final int API_UNAVAILABLE = 16;
|
||||
|
||||
/**
|
||||
* The Drive API requires external storage (such as an SD card), but no external storage is
|
||||
* mounted. This error is recoverable if the user installs external storage (if none is
|
||||
* present) and ensures that it is mounted (which may involve disabling USB storage mode,
|
||||
* formatting the storage, or other initialization as required by the device).
|
||||
* <p/>
|
||||
* This error should never be returned on a device with emulated external storage. On devices
|
||||
* with emulated external storage, the emulated "external storage" is always present regardless
|
||||
* of whether the device also has removable storage.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int DRIVE_EXTERNAL_STORAGE_REQUIRED = 1500;
|
||||
|
||||
private final int statusCode;
|
||||
private final PendingIntent pendingIntent;
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* Creates a connection result.
|
||||
*
|
||||
* @param statusCode The status code.
|
||||
*/
|
||||
public ConnectionResult(int statusCode) {
|
||||
this(statusCode, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a connection result.
|
||||
*
|
||||
* @param statusCode The status code.
|
||||
* @param pendingIntent A pending intent that will resolve the issue when started, or null.
|
||||
*/
|
||||
public ConnectionResult(int statusCode, PendingIntent pendingIntent) {
|
||||
this(statusCode, pendingIntent, getStatusString(statusCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a connection result.
|
||||
*
|
||||
* @param statusCode The status code.
|
||||
* @param pendingIntent A pending intent that will resolve the issue when started, or null.
|
||||
* @param message An additional error message for the connection result, or null.
|
||||
*/
|
||||
public ConnectionResult(int statusCode, PendingIntent pendingIntent, String message) {
|
||||
this.statusCode = statusCode;
|
||||
this.pendingIntent = pendingIntent;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
static String getStatusString(int statusCode) {
|
||||
switch (statusCode) {
|
||||
case -1:
|
||||
return "UNKNOWN";
|
||||
case 0:
|
||||
return "SUCCESS";
|
||||
case 1:
|
||||
return "SERVICE_MISSING";
|
||||
case 2:
|
||||
return "SERVICE_VERSION_UPDATE_REQUIRED";
|
||||
case 3:
|
||||
return "SERVICE_DISABLED";
|
||||
case 4:
|
||||
return "SIGN_IN_REQUIRED";
|
||||
case 5:
|
||||
return "INVALID_ACCOUNT";
|
||||
case 6:
|
||||
return "RESOLUTION_REQUIRED";
|
||||
case 7:
|
||||
return "NETWORK_ERROR";
|
||||
case 8:
|
||||
return "INTERNAL_ERROR";
|
||||
case 9:
|
||||
return "SERVICE_INVALID";
|
||||
case 10:
|
||||
return "DEVELOPER_ERROR";
|
||||
case 11:
|
||||
return "LICENSE_CHECK_FAILED";
|
||||
case 13:
|
||||
return "CANCELED";
|
||||
case 14:
|
||||
return "TIMEOUT";
|
||||
case 15:
|
||||
return "INTERRUPTED";
|
||||
case 16:
|
||||
return "API_UNAVAILABLE";
|
||||
case 17:
|
||||
return "SIGN_IN_FAILED";
|
||||
case 18:
|
||||
return "SERVICE_UPDATING";
|
||||
case 19:
|
||||
return "SERVICE_MISSING_PERMISSION";
|
||||
case 20:
|
||||
return "RESTRICTED_PROFILE";
|
||||
case 21:
|
||||
return "API_VERSION_UPDATE_REQUIRED";
|
||||
case 42:
|
||||
return "UPDATE_ANDROID_WEAR";
|
||||
case 99:
|
||||
return "UNFINISHED";
|
||||
case 1500:
|
||||
return "DRIVE_EXTERNAL_STORAGE_REQUIRED";
|
||||
default:
|
||||
return "UNKNOWN_ERROR_CODE(" + statusCode + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
} else if (!(o instanceof ConnectionResult)) {
|
||||
return false;
|
||||
} else {
|
||||
ConnectionResult r = (ConnectionResult)o;
|
||||
return statusCode == r.statusCode && pendingIntent == null ? r.pendingIntent == null : pendingIntent.equals(r.pendingIntent) && TextUtils.equals(message, r.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the type of error that interrupted connection.
|
||||
*
|
||||
* @return the error code, or {@link #SUCCESS} if no error occurred.
|
||||
*/
|
||||
public int getErrorCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an error message for connection result.
|
||||
*
|
||||
* @return the message
|
||||
*/
|
||||
public String getErrorMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* A pending intent to resolve the connection failure. This intent can be started with
|
||||
* {@link Activity#startIntentSenderForResult(IntentSender, int, Intent, int, int, int)} to
|
||||
* present UI to solve the issue.
|
||||
*
|
||||
* @return The pending intent to resolve the connection failure.
|
||||
*/
|
||||
public PendingIntent getResolution() {
|
||||
return pendingIntent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(new Object[]{statusCode, pendingIntent, message});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if calling {@link #startResolutionForResult(Activity, int)} will start
|
||||
* any intents requiring user interaction.
|
||||
*
|
||||
* @return {@code true} if there is a resolution that can be started.
|
||||
*/
|
||||
public boolean hasResolution() {
|
||||
return statusCode != 0 && pendingIntent != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the connection was successful.
|
||||
*
|
||||
* @return {@code true} if the connection was successful, {@code false} if there was an error.
|
||||
*/
|
||||
public boolean isSuccess() {
|
||||
return statusCode == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves an error by starting any intents requiring user interaction. See
|
||||
* {@link #SIGN_IN_REQUIRED}, and {@link #RESOLUTION_REQUIRED}.
|
||||
*
|
||||
* @param activity An Activity context to use to resolve the issue. The activity's
|
||||
* {@link Activity#onActivityResult} method will be invoked after the user
|
||||
* is done. If the resultCode is {@link Activity#RESULT_OK}, the application
|
||||
* should try to connect again.
|
||||
* @param requestCode The request code to pass to {@link Activity#onActivityResult}.
|
||||
* @throws IntentSender.SendIntentException If the resolution intent has been canceled or is no
|
||||
* longer able to execute the request.
|
||||
*/
|
||||
public void startResolutionForResult(Activity activity, int requestCode) throws
|
||||
IntentSender.SendIntentException {
|
||||
if (hasResolution()) {
|
||||
activity.startIntentSenderForResult(pendingIntent.getIntentSender(), requestCode, null, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -41,13 +41,13 @@ public interface GooglePlayServicesClient {
|
||||
void unregisterConnectionFailedListener(OnConnectionFailedListener listener);
|
||||
|
||||
@Deprecated
|
||||
public interface OnConnectionFailedListener {
|
||||
interface OnConnectionFailedListener {
|
||||
|
||||
void onConnectionFailed(ConnectionResult result);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public interface ConnectionCallbacks {
|
||||
interface ConnectionCallbacks {
|
||||
|
||||
void onConnected(Bundle connectionHint);
|
||||
|
||||
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2015 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 com.google.android.gms.common.api;
|
||||
|
||||
import org.microg.gms.common.PublicApi;
|
||||
import org.microg.gms.common.api.ApiBuilder;
|
||||
|
||||
/**
|
||||
* Describes a section of the Google Play Services API that should be made available. Instances of
|
||||
* this should be passed into {@link GoogleApiClient.Builder#addApi(Api)} to enable the appropriate
|
||||
* parts of Google Play Services.
|
||||
* <p/>
|
||||
* Google APIs are partitioned into sections which allow your application to configure only the
|
||||
* services it requires. Each Google API provides an API object which can be passed to
|
||||
* {@link GoogleApiClient.Builder#addApi(Api)} in order to configure and enable that functionality
|
||||
* in your {@link GoogleApiClient} instance.
|
||||
* <p/>
|
||||
* See {@link GoogleApiClient.Builder} for usage examples.
|
||||
*/
|
||||
@PublicApi
|
||||
public final class Api<O extends Api.ApiOptions> {
|
||||
|
||||
private final ApiBuilder<O> builder;
|
||||
|
||||
@PublicApi(exclude = true)
|
||||
public Api(ApiBuilder<O> builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@PublicApi(exclude = true)
|
||||
public ApiBuilder<O> getBuilder() {
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base interface for API options. These are used to configure specific parameters for
|
||||
* individual API surfaces. The default implementation has no parameters.
|
||||
*/
|
||||
@PublicApi
|
||||
public interface ApiOptions {
|
||||
/**
|
||||
* Base interface for {@link ApiOptions} in {@link Api}s that have options.
|
||||
*/
|
||||
@PublicApi
|
||||
interface HasOptions extends ApiOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Base interface for {@link ApiOptions} that are not required, don't exist.
|
||||
*/
|
||||
@PublicApi
|
||||
interface NotRequiredOptions extends ApiOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ApiOptions} implementation for {@link Api}s that do not take any options.
|
||||
*/
|
||||
@PublicApi
|
||||
final class NoOptions implements NotRequiredOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Base interface for {@link ApiOptions} that are optional.
|
||||
*/
|
||||
@PublicApi
|
||||
interface Optional extends HasOptions, NotRequiredOptions {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,494 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2015 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 com.google.android.gms.common.api;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.view.View;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
|
||||
import org.microg.gms.auth.AuthConstants;
|
||||
import org.microg.gms.common.PublicApi;
|
||||
import org.microg.gms.common.api.GoogleApiClientImpl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* The main entry point for Google Play services integration.
|
||||
* <p/>
|
||||
* GoogleApiClient is used with a variety of static methods. Some of these methods require that
|
||||
* GoogleApiClient be connected, some will queue up calls before GoogleApiClient is connected;
|
||||
* check the specific API documentation to determine whether you need to be connected.
|
||||
* <p/>
|
||||
* Before any operation is executed, the GoogleApiClient must be connected using the
|
||||
* {@link #connect()} method. The client is not considered connected until the
|
||||
* {@link ConnectionCallbacks#onConnected(Bundle)} callback has been called.
|
||||
* <p/>
|
||||
* When your app is done using this client, call {@link #disconnect()}, even if the async result
|
||||
* from {@link #connect()} has not yet been delivered.
|
||||
* <p/>
|
||||
* You should instantiate a client object in your Activity's {@link Activity#onCreate(Bundle)}
|
||||
* method and then call {@link #connect()} in {@link Activity#onStart()} and {@link #disconnect()}
|
||||
* in {@link Activity#onStop()}, regardless of the state.
|
||||
*/
|
||||
@PublicApi
|
||||
public interface GoogleApiClient {
|
||||
/**
|
||||
* Connects the client to Google Play services. Blocks until the connection either succeeds or
|
||||
* fails. This is not allowed on the UI thread.
|
||||
*
|
||||
* @return the result of the connection
|
||||
*/
|
||||
public ConnectionResult blockingConnect();
|
||||
|
||||
/**
|
||||
* Connects the client to Google Play services. Blocks until the connection is set or failed or
|
||||
* has timed out. This is not allowed on the UI thread.
|
||||
*
|
||||
* @param timeout the maximum time to wait
|
||||
* @param unit the time unit of the {@code timeout} argument
|
||||
* @return the result of the connection
|
||||
*/
|
||||
public ConnectionResult blockingConnect(long timeout, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Clears the account selected by the user and reconnects the client asking the user to pick an
|
||||
* account again if {@link Builder#useDefaultAccount()} was set.
|
||||
*
|
||||
* @return the pending result is fired once the default account has been cleared, but before
|
||||
* the client is reconnected - for that {@link ConnectionCallbacks} can be used.
|
||||
*/
|
||||
public PendingResult<Status> clearDefaultAccountAndReconnect();
|
||||
|
||||
/**
|
||||
* Connects the client to Google Play services. This method returns immediately, and connects
|
||||
* to the service in the background. If the connection is successful,
|
||||
* {@link ConnectionCallbacks#onConnected(Bundle)} is called and enqueued items are executed.
|
||||
* On a failure, {@link OnConnectionFailedListener#onConnectionFailed(ConnectionResult)} is
|
||||
* called.
|
||||
*/
|
||||
public void connect();
|
||||
|
||||
/**
|
||||
* Closes the connection to Google Play services. No calls can be made using this client after
|
||||
* calling this method. Any method calls that haven't executed yet will be canceled. That is
|
||||
* {@link ResultCallback#onResult(Result)} won't be called, if connection to the service hasn't
|
||||
* been established yet all calls already made will be canceled.
|
||||
*
|
||||
* @see #connect()
|
||||
*/
|
||||
public void disconnect();
|
||||
|
||||
/**
|
||||
* Checks if the client is currently connected to the service, so that requests to other
|
||||
* methods will succeed. Applications should guard client actions caused by the user with a
|
||||
* call to this method.
|
||||
*
|
||||
* @return {@code true} if the client is connected to the service.
|
||||
*/
|
||||
public boolean isConnected();
|
||||
|
||||
/**
|
||||
* Checks if the client is attempting to connect to the service.
|
||||
*
|
||||
* @return {@code true} if the client is attempting to connect to the service.
|
||||
*/
|
||||
public boolean isConnecting();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the specified listener is currently registered to receive connection
|
||||
* events.
|
||||
*
|
||||
* @param listener The listener to check for.
|
||||
* @return {@code true} if the specified listener is currently registered to receive connection
|
||||
* events.
|
||||
* @see #registerConnectionCallbacks(ConnectionCallbacks)
|
||||
* @see #unregisterConnectionCallbacks(ConnectionCallbacks)
|
||||
*/
|
||||
public boolean isConnectionCallbacksRegistered(ConnectionCallbacks listener);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the specified listener is currently registered to receive connection
|
||||
* failed events.
|
||||
*
|
||||
* @param listener The listener to check for.
|
||||
* @return {@code true} if the specified listener is currently registered to receive connection
|
||||
* failed events.
|
||||
* @see #registerConnectionFailedListener(OnConnectionFailedListener)
|
||||
* @see #unregisterConnectionFailedListener(OnConnectionFailedListener)
|
||||
*/
|
||||
public boolean isConnectionFailedListenerRegistered(OnConnectionFailedListener listener);
|
||||
|
||||
/**
|
||||
* Closes the current connection to Google Play services and creates a new connection.
|
||||
* <p/>
|
||||
* This method closes the current connection then returns immediately and reconnects to the
|
||||
* service in the background.
|
||||
* <p/>
|
||||
* After calling this method, your application will receive
|
||||
* {@link ConnectionCallbacks#onConnected(Bundle)} if the connection is successful, or
|
||||
* {@link OnConnectionFailedListener#onConnectionFailed(ConnectionResult)} if the connection
|
||||
* failed.
|
||||
*
|
||||
* @see #connect()
|
||||
* @see #disconnect()
|
||||
*/
|
||||
public void reconnect();
|
||||
|
||||
/**
|
||||
* Registers a listener to receive connection events from this {@link GoogleApiClient}. If the
|
||||
* service is already connected, the listener's {@link ConnectionCallbacks#onConnected(Bundle)}
|
||||
* method will be called immediately. Applications should balance calls to this method with
|
||||
* calls to {@link #unregisterConnectionCallbacks(ConnectionCallbacks)} to avoid leaking
|
||||
* resources.
|
||||
* <p/>
|
||||
* If the specified listener is already registered to receive connection events, this method
|
||||
* will not add a duplicate entry for the same listener, but will still call the listener's
|
||||
* {@link ConnectionCallbacks#onConnected(Bundle)} method if currently connected.
|
||||
* <p/>
|
||||
* Note that the order of messages received here may not be stable, so clients should not rely
|
||||
* on the order that multiple listeners receive events in.
|
||||
*
|
||||
* @param listener the listener where the results of the asynchronous {@link #connect()} call
|
||||
* are delivered.
|
||||
*/
|
||||
public void registerConnectionCallbacks(ConnectionCallbacks listener);
|
||||
|
||||
/**
|
||||
* Registers a listener to receive connection failed events from this {@link GoogleApiClient}.
|
||||
* Unlike {@link #registerConnectionCallbacks(ConnectionCallbacks)}, if the service is not
|
||||
* already connected, the listener's
|
||||
* {@link OnConnectionFailedListener#onConnectionFailed(ConnectionResult)} method will not be
|
||||
* called immediately. Applications should balance calls to this method with calls to
|
||||
* {@link #unregisterConnectionFailedListener(OnConnectionFailedListener)} to avoid leaking
|
||||
* resources.
|
||||
* <p/>
|
||||
* If the specified listener is already registered to receive connection failed events, this
|
||||
* method will not add a duplicate entry for the same listener.
|
||||
* <p/>
|
||||
* Note that the order of messages received here may not be stable, so clients should not rely
|
||||
* on the order that multiple listeners receive events in.
|
||||
*
|
||||
* @param listener the listener where the results of the asynchronous {@link #connect()} call
|
||||
* are delivered.
|
||||
*/
|
||||
public void registerConnectionFailedListener(OnConnectionFailedListener listener);
|
||||
|
||||
/**
|
||||
* Disconnects the client and stops automatic lifecycle management. Use this before creating a
|
||||
* new client (which might be necessary when switching accounts, changing the set of used APIs
|
||||
* etc.).
|
||||
* <p/>
|
||||
* This method must be called from the main thread.
|
||||
*
|
||||
* @param lifecycleActivity the activity managing the client's lifecycle.
|
||||
* @throws IllegalStateException if called from outside of the main thread.
|
||||
* @see Builder#enableAutoManage(FragmentActivity, int, OnConnectionFailedListener)
|
||||
*/
|
||||
public void stopAutoManager(FragmentActivity lifecycleActivity) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Removes a connection listener from this {@link GoogleApiClient}. Note that removing a
|
||||
* listener does not generate any callbacks.
|
||||
* <p/>
|
||||
* If the specified listener is not currently registered to receive connection events, this
|
||||
* method will have no effect.
|
||||
*
|
||||
* @param listener the listener to unregister.
|
||||
*/
|
||||
public void unregisterConnectionCallbacks(ConnectionCallbacks listener);
|
||||
|
||||
/**
|
||||
* Removes a connection failed listener from the {@link GoogleApiClient}. Note that removing a
|
||||
* listener does not generate any callbacks.
|
||||
* <p/>
|
||||
* If the specified listener is not currently registered to receive connection failed events,
|
||||
* this method will have no effect.
|
||||
*
|
||||
* @param listener the listener to unregister.
|
||||
*/
|
||||
public void unregisterConnectionFailedListener(OnConnectionFailedListener listener);
|
||||
|
||||
/**
|
||||
* Builder to configure a {@link GoogleApiClient}.
|
||||
*/
|
||||
@PublicApi
|
||||
public class Builder {
|
||||
private final Context context;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Builder to help construct the {@link GoogleApiClient} object.
|
||||
*
|
||||
* @param context The context to use for the connection.
|
||||
*/
|
||||
public Builder(Context context) {
|
||||
this.context = context;
|
||||
this.looper = context.getMainLooper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder to help construct the {@link GoogleApiClient} object.
|
||||
*
|
||||
* @param context The context to use for the connection.
|
||||
* @param connectedListener The listener where the results of the asynchronous
|
||||
* {@link #connect()} call are delivered.
|
||||
* @param connectionFailedListener The listener which will be notified if the connection
|
||||
* attempt fails.
|
||||
*/
|
||||
public Builder(Context context, ConnectionCallbacks connectedListener,
|
||||
OnConnectionFailedListener connectionFailedListener) {
|
||||
this(context);
|
||||
addConnectionCallbacks(connectedListener);
|
||||
addOnConnectionFailedListener(connectionFailedListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify which Apis are requested by your app. See {@link Api} for more information.
|
||||
*
|
||||
* @param api The Api requested by your app.
|
||||
* @param options Any additional parameters required for the specific AP
|
||||
* @see Api
|
||||
*/
|
||||
public <O extends Api.ApiOptions.HasOptions> Builder addApi(Api<O> api, O options) {
|
||||
apis.put(api, options);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify which Apis are requested by your app. See {@link Api} for more information.
|
||||
*
|
||||
* @param api The Api requested by your app.
|
||||
* @see Api
|
||||
*/
|
||||
public Builder addApi(Api<? extends Api.ApiOptions.NotRequiredOptions> api) {
|
||||
apis.put(api, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener to receive connection events from this {@link GoogleApiClient}.
|
||||
* Applications should balance calls to this method with calls to
|
||||
* {@link #unregisterConnectionCallbacks(ConnectionCallbacks)} to avoid
|
||||
* leaking resources.
|
||||
* <p/>
|
||||
* If the specified listener is already registered to receive connection events, this
|
||||
* method will not add a duplicate entry for the same listener.
|
||||
* <p/>
|
||||
* Note that the order of messages received here may not be stable, so clients should not
|
||||
* rely on the order that multiple listeners receive events in.
|
||||
*
|
||||
* @param listener the listener where the results of the asynchronous {@link #connect()}
|
||||
* call are delivered.
|
||||
*/
|
||||
public Builder addConnectionCallbacks(ConnectionCallbacks listener) {
|
||||
connectionCallbacks.add(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to register to receive connection failed events from this
|
||||
* {@link GoogleApiClient}. Applications should balance calls to this method with calls to
|
||||
* {@link #unregisterConnectionFailedListener(OnConnectionFailedListener)} to avoid
|
||||
* leaking resources.
|
||||
* <p/>
|
||||
* If the specified listener is already registered to receive connection failed events,
|
||||
* this method will not add a duplicate entry for the same listener.
|
||||
* <p/>
|
||||
* Note that the order of messages received here may not be stable, so clients should not
|
||||
* rely on the order that multiple listeners receive events in.
|
||||
*
|
||||
* @param listener the listener where the results of the asynchronous {@link #connect()}
|
||||
* call are delivered.
|
||||
*/
|
||||
public Builder addOnConnectionFailedListener(OnConnectionFailedListener listener) {
|
||||
connectionFailedListeners.add(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the OAuth 2.0 scopes requested by your app. See
|
||||
* {@link com.google.android.gms.common.Scopes} for more information.
|
||||
*
|
||||
* @param scope The OAuth 2.0 scopes requested by your app.
|
||||
* @see com.google.android.gms.common.Scopes
|
||||
*/
|
||||
public Builder addScope(Scope scope) {
|
||||
scopes.add(scope.getScopeUri());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new {@link GoogleApiClient} object for communicating with the Google APIs.
|
||||
*
|
||||
* @return The {@link GoogleApiClient} object.
|
||||
*/
|
||||
public GoogleApiClient build() {
|
||||
return new GoogleApiClientImpl(context, looper, getAccountInfo(), apis,
|
||||
connectionCallbacks, connectionFailedListeners, clientId);
|
||||
}
|
||||
|
||||
private AccountInfo getAccountInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Builder enableAutoManage(FragmentActivity fragmentActivity, int cliendId,
|
||||
OnConnectionFailedListener unresolvedConnectionFailedListener)
|
||||
throws NullPointerException, IllegalArgumentException, IllegalStateException {
|
||||
this.fragmentActivity = fragmentActivity;
|
||||
this.clientId = cliendId;
|
||||
this.unresolvedConnectionFailedListener = unresolvedConnectionFailedListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify an account name on the device that should be used. If this is never called, the
|
||||
* client will use the current default account for Google Play services for this
|
||||
* application.
|
||||
*
|
||||
* @param accountName The account name on the device that should be used by
|
||||
* {@link GoogleApiClient}.
|
||||
*/
|
||||
public Builder setAccountName(String accountName) {
|
||||
this.accountName = accountName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the part of the screen at which games service popups (for example,
|
||||
* "welcome back" or "achievement unlocked" popups) will be displayed using gravity.
|
||||
*
|
||||
* @param gravityForPopups The gravity which controls the placement of games service popups.
|
||||
*/
|
||||
public Builder setGravityForPopups(int gravityForPopups) {
|
||||
this.gravityForPopups = gravityForPopups;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a {@link Handler} to indicate which thread to use when invoking callbacks. Will not
|
||||
* be used directly to handle callbacks. If this is not called then the application's main
|
||||
* thread will be used.
|
||||
*/
|
||||
public Builder setHandler(Handler handler) {
|
||||
this.looper = handler.getLooper();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link View} to use as a content view for popups.
|
||||
*
|
||||
* @param viewForPopups The view to use as a content view for popups. View cannot be null.
|
||||
*/
|
||||
public Builder setViewForPopups(View viewForPopups) {
|
||||
this.viewForPopups = viewForPopups;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that the default account should be used when connecting to services.
|
||||
*/
|
||||
public Builder useDefaultAccount() {
|
||||
this.accountName = AuthConstants.DEFAULT_ACCOUNT;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides callbacks that are called when the client is connected or disconnected from the
|
||||
* service. Most applications implement {@link #onConnected(Bundle)} to start making requests.
|
||||
*/
|
||||
@PublicApi
|
||||
public interface ConnectionCallbacks {
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* After calling {@link #connect()}, this method will be invoked asynchronously when the
|
||||
* connect request has successfully completed. After this callback, the application can
|
||||
* make requests on other methods provided by the client and expect that no user
|
||||
* intervention is required to call methods that use account and scopes provided to the
|
||||
* client constructor.
|
||||
* <p/>
|
||||
* Note that the contents of the {@code connectionHint} Bundle are defined by the specific
|
||||
* services. Please see the documentation of the specific implementation of
|
||||
* {@link GoogleApiClient} you are using for more information.
|
||||
*
|
||||
* @param connectionHint Bundle of data provided to clients by Google Play services. May
|
||||
* be null if no content is provided by the service.
|
||||
*/
|
||||
void onConnected(Bundle connectionHint);
|
||||
|
||||
/**
|
||||
* Called when the client is temporarily in a disconnected state. This can happen if there
|
||||
* is a problem with the remote service (e.g. a crash or resource problem causes it to be
|
||||
* killed by the system). When called, all requests have been canceled and no outstanding
|
||||
* listeners will be executed. GoogleApiClient will automatically attempt to restore the
|
||||
* connection. Applications should disable UI components that require the service, and wait
|
||||
* for a call to {@link #onConnected(Bundle)} to re-enable them.
|
||||
*
|
||||
* @param cause The reason for the disconnection. Defined by constants {@code CAUSE_*}.
|
||||
*/
|
||||
void onConnectionSuspended(int cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides callbacks for scenarios that result in a failed attempt to connect the client to
|
||||
* the service. See {@link ConnectionResult} for a list of error codes and suggestions for
|
||||
* resolution.
|
||||
*/
|
||||
@PublicApi
|
||||
public interface OnConnectionFailedListener {
|
||||
/**
|
||||
* Called when there was an error connecting the client to the service.
|
||||
*
|
||||
* @param result A {@link ConnectionResult} that can be used for resolving the error, and
|
||||
* deciding what sort of error occurred. To resolve the error, the resolution
|
||||
* must be started from an activity with a non-negative {@code requestCode}
|
||||
* passed to {@link ConnectionResult#startResolutionForResult(Activity, int)}.
|
||||
* Applications should implement {@link Activity#onActivityResult} in their
|
||||
* Activity to call {@link #connect()} again if the user has resolved the
|
||||
* issue (resultCode is {@link Activity#RESULT_OK}).
|
||||
*/
|
||||
void onConnectionFailed(ConnectionResult result);
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2015 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 com.google.android.gms.common.api;
|
||||
|
||||
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);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2015 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 com.google.android.gms.common.api;
|
||||
|
||||
/**
|
||||
* Represents a resource, or a holder of resources, which may be released once they are no longer
|
||||
* needed.
|
||||
*/
|
||||
public interface Releasable {
|
||||
public void release();
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2015 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 com.google.android.gms.common.api;
|
||||
|
||||
/**
|
||||
* An interface for receiving a {@link Result} from a {@link PendingResult} as an asynchronous
|
||||
* callback.
|
||||
*/
|
||||
public interface ResultCallback<R extends Result> {
|
||||
/**
|
||||
* Called when the {@link Result} is ready. It is the responsibility of each callback to
|
||||
* release any resources associated with the result. Some result types may implement
|
||||
* {@link Releasable}, in which case {@link Releasable#release()} should be used to free the
|
||||
* associated resources.
|
||||
*
|
||||
* @param result The result from the API call. May not be null.
|
||||
*/
|
||||
public void onResult(R result);
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.microg.gms.common;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.ServiceConnection;
|
||||
@ -27,6 +28,7 @@ import android.util.Log;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.internal.GetServiceRequest;
|
||||
import com.google.android.gms.common.internal.IGmsCallbacks;
|
||||
import com.google.android.gms.common.internal.IGmsServiceBroker;
|
||||
|
||||
@ -41,18 +43,31 @@ public abstract class GmsClient<I extends IInterface> implements ApiConnection {
|
||||
protected ConnectionState state = ConnectionState.NOT_CONNECTED;
|
||||
private ServiceConnection serviceConnection;
|
||||
private I serviceInterface;
|
||||
private String actionString;
|
||||
|
||||
protected int serviceId = -1;
|
||||
protected Account account = null;
|
||||
protected Bundle extras = new Bundle();
|
||||
|
||||
public GmsClient(Context context, GoogleApiClient.ConnectionCallbacks callbacks,
|
||||
GoogleApiClient.OnConnectionFailedListener connectionFailedListener) {
|
||||
GoogleApiClient.OnConnectionFailedListener connectionFailedListener, String actionString) {
|
||||
this.context = context;
|
||||
this.callbacks = callbacks;
|
||||
this.connectionFailedListener = connectionFailedListener;
|
||||
this.actionString = actionString;
|
||||
}
|
||||
|
||||
protected abstract String getActionString();
|
||||
|
||||
protected abstract void onConnectedToBroker(IGmsServiceBroker broker, GmsCallbacks callbacks)
|
||||
throws RemoteException;
|
||||
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.extras = new Bundle();
|
||||
request.packageName = context.getPackageName();
|
||||
request.account = account;
|
||||
request.extras = extras;
|
||||
broker.getService(callbacks, request);
|
||||
}
|
||||
|
||||
protected abstract I interfaceFromBinder(IBinder binder);
|
||||
|
||||
@ -64,12 +79,10 @@ public abstract class GmsClient<I extends IInterface> implements ApiConnection {
|
||||
}
|
||||
state = ConnectionState.CONNECTING;
|
||||
if (serviceConnection != null) {
|
||||
MultiConnectionKeeper.getInstance(context)
|
||||
.unbind(getActionString(), serviceConnection);
|
||||
MultiConnectionKeeper.getInstance(context).unbind(actionString, serviceConnection);
|
||||
}
|
||||
serviceConnection = new GmsServiceConnection();
|
||||
if (!MultiConnectionKeeper.getInstance(context).bind(getActionString(),
|
||||
serviceConnection)) {
|
||||
if (!MultiConnectionKeeper.getInstance(context).bind(actionString, serviceConnection)) {
|
||||
state = ConnectionState.ERROR;
|
||||
handleConnectionFailed();
|
||||
}
|
||||
@ -90,7 +103,7 @@ public abstract class GmsClient<I extends IInterface> implements ApiConnection {
|
||||
}
|
||||
serviceInterface = null;
|
||||
if (serviceConnection != null) {
|
||||
MultiConnectionKeeper.getInstance(context).unbind(getActionString(), serviceConnection);
|
||||
MultiConnectionKeeper.getInstance(context).unbind(actionString, serviceConnection);
|
||||
serviceConnection = null;
|
||||
}
|
||||
state = ConnectionState.NOT_CONNECTED;
|
||||
|
@ -23,25 +23,29 @@ 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.ApiConnection;
|
||||
import org.microg.gms.common.api.GoogleApiClientImpl;
|
||||
|
||||
public class GmsConnector<C extends ApiConnection, R extends Result, O extends Api.ApiOptions> {
|
||||
public class GmsConnector<C extends ApiConnection, R extends Result> {
|
||||
private static final String TAG = "GmsConnector";
|
||||
|
||||
private final GoogleApiClientImpl apiClient;
|
||||
private final Api<O> api;
|
||||
private final Api api;
|
||||
private final Callback<C, R> callback;
|
||||
|
||||
public GmsConnector(GoogleApiClient apiClient, Api<O> api, 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 ApiConnection, 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()");
|
||||
@ -54,8 +58,12 @@ public class GmsConnector<C extends ApiConnection, R extends Result, O extends A
|
||||
return result;
|
||||
}
|
||||
|
||||
public static interface Callback<C, R> {
|
||||
public R onClientAvailable(C client) throws RemoteException;
|
||||
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 {
|
||||
@ -66,10 +74,15 @@ public class GmsConnector<C extends ApiConnection, R extends Result, O extends A
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
Log.d(TAG, "Handler : handleMessage");
|
||||
AbstractPendingResult<R> result = (AbstractPendingResult<R>) msg.obj;
|
||||
final AbstractPendingResult<R> result = (AbstractPendingResult<R>) msg.obj;
|
||||
try {
|
||||
C connection = (C)apiClient.getApiConnection(api);
|
||||
result.deliverResult(callback.onClientAvailable(connection));
|
||||
C connection = (C) apiClient.getApiConnection(api);
|
||||
callback.onClientAvailable(connection, new GmsConnector.Callback.ResultProvider<R>() {
|
||||
@Override
|
||||
public void onResultAvailable(R realResult) {
|
||||
result.deliverResult(realResult);
|
||||
}
|
||||
});
|
||||
} catch (RemoteException ignored) {
|
||||
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2015 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.api;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
|
||||
import com.google.android.gms.common.api.AccountInfo;
|
||||
import com.google.android.gms.common.api.Api;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
|
||||
public interface ApiBuilder<O extends Api.ApiOptions> {
|
||||
ApiConnection build(Context context, Looper looper, O options, AccountInfo accountInfo,
|
||||
GoogleApiClient.ConnectionCallbacks callbacks,
|
||||
GoogleApiClient.OnConnectionFailedListener connectionFailedListener);
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2015 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.api;
|
||||
|
||||
public interface ApiConnection {
|
||||
void connect();
|
||||
|
||||
void disconnect();
|
||||
|
||||
boolean isConnected();
|
||||
|
||||
boolean isConnecting();
|
||||
}
|
@ -1,223 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2015 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.api;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.api.AccountInfo;
|
||||
import com.google.android.gms.common.api.Api;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.api.PendingResult;
|
||||
import com.google.android.gms.common.api.Status;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class GoogleApiClientImpl implements GoogleApiClient {
|
||||
private static final String TAG = "GmsApiClientImpl";
|
||||
|
||||
private final Context context;
|
||||
private final Looper looper;
|
||||
private final AccountInfo accountInfo;
|
||||
private final Map<Api, Api.ApiOptions> apis = new HashMap<Api, Api.ApiOptions>();
|
||||
private final Map<Api, ApiConnection> apiConnections = new HashMap<Api, ApiConnection>();
|
||||
private final Handler handler;
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public GoogleApiClientImpl(Context context, Looper looper, AccountInfo accountInfo,
|
||||
Map<Api, Api.ApiOptions> apis,
|
||||
Set<ConnectionCallbacks> connectionCallbacks,
|
||||
Set<OnConnectionFailedListener> connectionFailedListeners, int clientId) {
|
||||
this.context = context;
|
||||
this.looper = looper;
|
||||
this.handler = new Handler(looper);
|
||||
this.accountInfo = accountInfo;
|
||||
this.apis.putAll(apis);
|
||||
this.connectionCallbacks.addAll(connectionCallbacks);
|
||||
this.connectionFailedListeners.addAll(connectionFailedListeners);
|
||||
this.clientId = clientId;
|
||||
|
||||
for (Api api : apis.keySet()) {
|
||||
apiConnections.put(api, api.getBuilder().build(context, looper,
|
||||
apis.get(api), accountInfo, baseConnectionCallbacks,
|
||||
baseConnectionFailedListener));
|
||||
}
|
||||
}
|
||||
|
||||
public Looper getLooper() {
|
||||
return looper;
|
||||
}
|
||||
|
||||
public ApiConnection getApiConnection(Api api) {
|
||||
return apiConnections.get(api);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionResult blockingConnect() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionResult blockingConnect(long timeout, TimeUnit unit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<Status> clearDefaultAccountAndReconnect() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void connect() {
|
||||
Log.d(TAG, "connect()");
|
||||
if (isConnected() || isConnecting()) {
|
||||
Log.d(TAG, "Already connected/connecting, nothing to do");
|
||||
return;
|
||||
}
|
||||
for (ApiConnection connection : apiConnections.values()) {
|
||||
if (!connection.isConnected()) {
|
||||
connection.connect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void disconnect() {
|
||||
Log.d(TAG, "disconnect()");
|
||||
for (ApiConnection connection : apiConnections.values()) {
|
||||
if (connection.isConnected()) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isConnected() {
|
||||
for (ApiConnection connection : apiConnections.values()) {
|
||||
if (!connection.isConnected()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isConnecting() {
|
||||
for (ApiConnection connection : apiConnections.values()) {
|
||||
if (connection.isConnecting()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnectionCallbacksRegistered(ConnectionCallbacks listener) {
|
||||
return connectionCallbacks.contains(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnectionFailedListenerRegistered(
|
||||
OnConnectionFailedListener listener) {
|
||||
return connectionFailedListeners.contains(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reconnect() {
|
||||
Log.d(TAG, "reconnect()");
|
||||
disconnect();
|
||||
connect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerConnectionCallbacks(ConnectionCallbacks listener) {
|
||||
connectionCallbacks.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerConnectionFailedListener(OnConnectionFailedListener listener) {
|
||||
connectionFailedListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopAutoManager(FragmentActivity lifecycleActivity) throws IllegalStateException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterConnectionCallbacks(ConnectionCallbacks listener) {
|
||||
connectionCallbacks.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterConnectionFailedListener(OnConnectionFailedListener listener) {
|
||||
connectionFailedListeners.remove(listener);
|
||||
}
|
||||
|
||||
private class Handler extends android.os.Handler {
|
||||
private Handler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.what == 0 && msg.obj instanceof Runnable) {
|
||||
((Runnable) msg.obj).run();
|
||||
} else {
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendRunnable(Runnable runnable) {
|
||||
sendMessage(obtainMessage(1, runnable));
|
||||
}
|
||||
}
|
||||
}
|
1
play-services-basement
Symbolic link
1
play-services-basement
Symbolic link
@ -0,0 +1 @@
|
||||
extern/GmsApi/play-services-basement
|
@ -15,10 +15,10 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.microg.gms.cast">
|
||||
<manifest package="org.microg.gms.cast"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-sdk android:minSdkVersion="9" />
|
||||
<uses-sdk android:minSdkVersion="9"/>
|
||||
|
||||
<application />
|
||||
<application/>
|
||||
</manifest>
|
||||
|
@ -1 +0,0 @@
|
||||
extern/GmsApi/play-services-common-api/
|
@ -22,7 +22,6 @@ import android.os.Looper;
|
||||
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;
|
||||
@ -33,6 +32,7 @@ import com.google.android.gms.location.LocationRequest;
|
||||
import com.google.android.gms.location.LocationServices;
|
||||
|
||||
import org.microg.gms.common.GmsConnector;
|
||||
import org.microg.gms.common.api.ApiConnection;
|
||||
|
||||
public class FusedLocationProviderApiImpl implements FusedLocationProviderApi {
|
||||
private static final String TAG = "GmsFusedApiImpl";
|
||||
@ -50,7 +50,7 @@ public class FusedLocationProviderApiImpl implements FusedLocationProviderApi {
|
||||
|
||||
@Override
|
||||
public PendingResult requestLocationUpdates(GoogleApiClient client,
|
||||
final LocationRequest request, final LocationListener listener) {
|
||||
final LocationRequest request, final LocationListener listener) {
|
||||
return callVoid(client, new Runnable() {
|
||||
@Override
|
||||
public void run(LocationClientImpl client) throws RemoteException {
|
||||
@ -61,8 +61,8 @@ public class FusedLocationProviderApiImpl implements FusedLocationProviderApi {
|
||||
|
||||
@Override
|
||||
public PendingResult requestLocationUpdates(GoogleApiClient client,
|
||||
final LocationRequest request, final LocationListener listener,
|
||||
final Looper looper) {
|
||||
final LocationRequest request, final LocationListener listener,
|
||||
final Looper looper) {
|
||||
return callVoid(client, new Runnable() {
|
||||
@Override
|
||||
public void run(LocationClientImpl client) throws RemoteException {
|
||||
@ -73,7 +73,7 @@ public class FusedLocationProviderApiImpl implements FusedLocationProviderApi {
|
||||
|
||||
@Override
|
||||
public PendingResult requestLocationUpdates(GoogleApiClient client,
|
||||
final LocationRequest request, final PendingIntent callbackIntent) {
|
||||
final LocationRequest request, final PendingIntent callbackIntent) {
|
||||
return callVoid(client, new Runnable() {
|
||||
@Override
|
||||
public void run(LocationClientImpl client) throws RemoteException {
|
||||
@ -84,7 +84,7 @@ public class FusedLocationProviderApiImpl implements FusedLocationProviderApi {
|
||||
|
||||
@Override
|
||||
public PendingResult removeLocationUpdates(GoogleApiClient client,
|
||||
final LocationListener listener) {
|
||||
final LocationListener listener) {
|
||||
return callVoid(client, new Runnable() {
|
||||
@Override
|
||||
public void run(LocationClientImpl client) throws RemoteException {
|
||||
@ -95,7 +95,7 @@ public class FusedLocationProviderApiImpl implements FusedLocationProviderApi {
|
||||
|
||||
@Override
|
||||
public PendingResult removeLocationUpdates(GoogleApiClient client,
|
||||
final PendingIntent callbackIntent) {
|
||||
final PendingIntent callbackIntent) {
|
||||
return callVoid(client, new Runnable() {
|
||||
@Override
|
||||
public void run(LocationClientImpl client) throws RemoteException {
|
||||
@ -125,15 +125,13 @@ public class FusedLocationProviderApiImpl implements FusedLocationProviderApi {
|
||||
}
|
||||
|
||||
private PendingResult callVoid(GoogleApiClient client, final Runnable runnable) {
|
||||
return new GmsConnector<LocationClientImpl, Result, Api.ApiOptions.NoOptions>(client, LocationServices.API,
|
||||
new GmsConnector.Callback<LocationClientImpl, Result>() {
|
||||
@Override
|
||||
public Result onClientAvailable(LocationClientImpl client) throws
|
||||
RemoteException {
|
||||
runnable.run(client);
|
||||
return Status.SUCCESS;
|
||||
}
|
||||
}).connect();
|
||||
return GmsConnector.call(client, LocationServices.API, new GmsConnector.Callback<LocationClientImpl, Result>() {
|
||||
@Override
|
||||
public void onClientAvailable(LocationClientImpl client, ResultProvider<Result> resultProvider) throws RemoteException {
|
||||
runnable.run(client);
|
||||
resultProvider.onResultAvailable(Status.SUCCESS);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private interface Runnable {
|
||||
|
@ -32,12 +32,7 @@ import org.microg.gms.common.GmsService;
|
||||
public abstract class GoogleLocationManagerClient extends GmsClient<IGoogleLocationManagerService> {
|
||||
public GoogleLocationManagerClient(Context context, GoogleApiClient.ConnectionCallbacks
|
||||
callbacks, GoogleApiClient.OnConnectionFailedListener connectionFailedListener) {
|
||||
super(context, callbacks, connectionFailedListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getActionString() {
|
||||
return GmsService.LOCATION_MANAGER.ACTION;
|
||||
super(context, callbacks, connectionFailedListener, GmsService.LOCATION_MANAGER.ACTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,5 +48,5 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':play-services-common-api')
|
||||
compile project(':play-services-basement')
|
||||
}
|
||||
|
@ -42,6 +42,12 @@ android {
|
||||
versionName getMyVersionName()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDirs += 'src/main/protos-java'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_6
|
||||
}
|
||||
@ -50,4 +56,5 @@ android {
|
||||
dependencies {
|
||||
compile project(':play-services-base')
|
||||
compile project(':play-services-wearable-api')
|
||||
compile 'com.squareup.wire:wire-runtime:1.6.1'
|
||||
}
|
||||
|
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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 com.google.android.gms.wearable;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.api.GoogleApiClient.Builder;
|
||||
import com.google.android.gms.common.api.PendingResult;
|
||||
import com.google.android.gms.common.api.Result;
|
||||
import com.google.android.gms.common.api.Status;
|
||||
|
||||
import org.microg.gms.common.PublicApi;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Exposes an API to learn about capabilities provided by nodes on the Wear network.
|
||||
* <p/>
|
||||
* Capabilities are local to an application.
|
||||
*/
|
||||
@PublicApi
|
||||
public interface CapabilityApi {
|
||||
/**
|
||||
* Capability changed action for use in manifest-based listener filters.
|
||||
* <p/>
|
||||
* Capability events do not support filtering by host, but can be filtered by path.
|
||||
*
|
||||
* @see WearableListenerService
|
||||
*/
|
||||
String ACTION_CAPABILITY_CHANGED = "com.google.android.gms.wearable.CAPABILITY_CHANGED";
|
||||
|
||||
/**
|
||||
* Filter type for {@link #getCapability(GoogleApiClient, String, int)}, {@link #getAllCapabilities(GoogleApiClient, int)}:
|
||||
* If this filter is set then the full set of nodes that declare the given capability will be
|
||||
* included in the capability's CapabilityInfo.
|
||||
*/
|
||||
int FILTER_ALL = 0;
|
||||
|
||||
/**
|
||||
* Filter type for {@link #addListener(GoogleApiClient, CapabilityListener, Uri, int)}, if this
|
||||
* filter is set, the given URI will be taken as a literal path, and the operation will apply
|
||||
* to the matching capability only.
|
||||
*/
|
||||
int FILTER_LITERAL = 0;
|
||||
|
||||
/**
|
||||
* Filter type for {@link #addListener(GoogleApiClient, CapabilityListener, Uri, int)}, if this
|
||||
* filter is set, the given URI will be taken as a path prefix, and the operation will apply
|
||||
* to all matching capabilities.
|
||||
*/
|
||||
int FILTER_PREFIX = 1;
|
||||
|
||||
/**
|
||||
* Filter type for {@link #getCapability(GoogleApiClient, String, int)}, {@link #getAllCapabilities(GoogleApiClient, int):
|
||||
* If this filter is set then only reachable nodes that declare the given capability will be
|
||||
* included in the capability's CapabilityInfo.
|
||||
*/
|
||||
int FILTER_REACHABLE = 1;
|
||||
|
||||
/**
|
||||
* Registers a listener to be notified of a specific capability being added to or removed from
|
||||
* the Wear network. Calls to this method should be balanced with {@link #removeCapabilityListener(GoogleApiClient, CapabilityListener, String)}
|
||||
* to avoid leaking resources.
|
||||
* <p/>
|
||||
* Listener events will be called on the main thread, or the handler specified on {@code client}
|
||||
* when it was built (using {@link Builder#setHandler(Handler)}).
|
||||
* <p/>
|
||||
* Callers wishing to be notified of events in the background should use {@link WearableListenerService}.
|
||||
*/
|
||||
PendingResult<Status> addCapabilityListener(GoogleApiClient client, CapabilityListener listener, String capability);
|
||||
|
||||
/**
|
||||
* Registers a listener to be notified of capabilities being added to or removed from the Wear
|
||||
* network. Calls to this method should be balanced with {@link #removeListener(GoogleApiClient, CapabilityListener)}
|
||||
* to avoid leaking resources.
|
||||
* <p/>
|
||||
* {@code uri} and {@code filterType} can be used to filter the capability changes sent to the
|
||||
* listener. For example, if {@code uri} and {@code filterType} create a prefix filter, then
|
||||
* only capabilities matching that prefix will be notified. The {@code uri} follows the rules
|
||||
* of the {@code <data>} element of {@code <intent-filter>}. The path is ignored if a URI host
|
||||
* is not specified. To match capabilities by name or name prefix, the host must be {@code *}. i.e:
|
||||
* <p/>
|
||||
* <pre>wear://* /<capability_name></pre>
|
||||
* Listener events will be called on the main thread, or the handler specified on {@code client}
|
||||
* when it was built (using {@link Builder#setHandler(Handler)}).
|
||||
*
|
||||
* Callers wishing to be notified of events in the background should use WearableListenerService.
|
||||
*/
|
||||
PendingResult<Status> addListener(GoogleApiClient client, CapabilityListener listener, Uri uri, @CapabilityFilterType int filterType);
|
||||
|
||||
/**
|
||||
* Announces that a capability has become available on the local node.
|
||||
*/
|
||||
PendingResult<AddLocalCapabilityResult> addLocalCapability(GoogleApiClient client, String capability);
|
||||
|
||||
/**
|
||||
* Returns information about all capabilities, including the nodes that declare those
|
||||
* capabilities. The filter parameter controls whether all nodes are returned, {@link #FILTER_ALL},
|
||||
* or only those that are currently reachable by this node, {@link #FILTER_REACHABLE}.
|
||||
* <p/>
|
||||
* The local node will never be returned in the set of nodes.
|
||||
*/
|
||||
PendingResult<GetAllCapabilitiesResult> getAllCapabilities(GoogleApiClient client, @NodeFilterType int nodeFilter);
|
||||
|
||||
/**
|
||||
* Returns information about a capabilities, including the nodes that declare this capability.
|
||||
* The filter parameter controls whether all nodes are returned, {@link #FILTER_ALL}, or only
|
||||
* those that are currently reachable by this node, {@link #FILTER_REACHABLE}.
|
||||
* <p/>
|
||||
* The local node will never be returned in the set of nodes.
|
||||
*/
|
||||
PendingResult<GetCapabilityResult> getCapability(GoogleApiClient client, String capability, @NodeFilterType int nodeFilter);
|
||||
|
||||
/**
|
||||
* Removes a listener which was previously added through {@link #addCapabilityListener(GoogleApiClient, CapabilityListener, String)}.
|
||||
* The listener is only removed from listening for the capability provided and will continue to
|
||||
* receive messages for any other capabilities it was previously registered for that have not
|
||||
* also been removed.
|
||||
*/
|
||||
PendingResult<Status> removeCapabilityListener(GoogleApiClient client, CapabilityListener listener, String capability);
|
||||
|
||||
/**
|
||||
* Removes a listener which was previously added through {@link #addListener(GoogleApiClient, CapabilityListener, Uri, int)}.
|
||||
* The listener is only removed from listening for the capability provided and will continue to
|
||||
* receive messages for any other capabilities it was previously registered for that have not
|
||||
* also been removed.
|
||||
*/
|
||||
PendingResult<Status> removeListener(GoogleApiClient client, CapabilityListener listener);
|
||||
|
||||
/**
|
||||
* Announces that a capability is no longer available on the local node. Note: this will not
|
||||
* remove any capabilities announced in the Manifest for an app.
|
||||
*/
|
||||
PendingResult<RemoveLocalCapabilityResult> removeLocalCapability(GoogleApiClient client, String capability);
|
||||
|
||||
/**
|
||||
* Result returned from {@link #addLocalCapability(GoogleApiClient, String)}
|
||||
*/
|
||||
interface AddLocalCapabilityResult extends Result {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface CapabilityFilterType {
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for changes in the reachable nodes providing a capability.
|
||||
*/
|
||||
interface CapabilityListener {
|
||||
void onCapabilityChanged(CapabilityInfo capabilityInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Result returned from {@link #getAllCapabilities(GoogleApiClient, int)}
|
||||
*/
|
||||
interface GetAllCapabilitiesResult extends Result {
|
||||
Map<String, CapabilityInfo> getAllCapabilities();
|
||||
}
|
||||
|
||||
/**
|
||||
* Result returned from {@link #getCapability(GoogleApiClient, String, int)}
|
||||
*/
|
||||
interface GetCapabilityResult extends Result {
|
||||
CapabilityInfo getCapability();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface NodeFilterType {
|
||||
}
|
||||
|
||||
/**
|
||||
* Result returned from {@link #removeLocalCapability(GoogleApiClient, String)}
|
||||
*/
|
||||
interface RemoveLocalCapabilityResult extends Result {
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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 com.google.android.gms.wearable;
|
||||
|
||||
import com.google.android.gms.wearable.ChannelApi.ChannelListener;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A subclass of {@link IOException} which can be thrown from the streams returned by
|
||||
* {@link Channel#getInputStream(GoogleApiClient)} and {@link Channel#getOutputStream(GoogleApiClient)}.
|
||||
*/
|
||||
public class ChannelIOException extends IOException {
|
||||
|
||||
private int closeReason;
|
||||
private int appSpecificErrorCode;
|
||||
|
||||
public ChannelIOException(String message, int closeReason, int appSpecificErrorCode) {
|
||||
super(message);
|
||||
this.closeReason = closeReason;
|
||||
this.appSpecificErrorCode = appSpecificErrorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the app-specific error code passed to {@link Channel#close(GoogleApiClient, int)} if
|
||||
* that's the reason for the stream closing, or {@code 0} otherwise.
|
||||
*/
|
||||
public int getAppSpecificErrorCode() {
|
||||
return appSpecificErrorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one of {@link ChannelListener#CLOSE_REASON_NORMAL}, {@link ChannelListener#CLOSE_REASON_DISCONNECTED},
|
||||
* {@link ChannelListener#CLOSE_REASON_REMOTE_CLOSE}, or {@link ChannelListener#CLOSE_REASON_LOCAL_CLOSE},
|
||||
* to indicate the reason for the stream closing.
|
||||
*/
|
||||
public int getCloseReason() {
|
||||
return closeReason;
|
||||
}
|
||||
}
|
@ -19,12 +19,29 @@ package com.google.android.gms.wearable;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.microg.gms.common.PublicApi;
|
||||
import org.microg.gms.wearable.databundle.DataBundleUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.ASSET_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.BOOLEAN_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.BYTE_ARRAY_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.BYTE_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.DATAMAP_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.DOUBLE_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.FLOAT_ARRAY_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.FLOAT_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.INTEGER_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.LIST_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.LONG_ARRAY_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.LONG_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.STRING_ARRAY_TYPE_CODE;
|
||||
import static org.microg.gms.wearable.databundle.DataBundleUtil.STRING_TYPE_CODE;
|
||||
|
||||
/**
|
||||
* A map of data supported by {@link PutDataMapRequest} and {@link DataMapItem}s. DataMap may
|
||||
* convert to and from Bundles, but will drop any types not explicitly supported by DataMap in the
|
||||
@ -74,6 +91,40 @@ public class DataMap {
|
||||
return o instanceof DataMap && data.equals(((DataMap) o).data);
|
||||
}
|
||||
|
||||
public StoredType getType(String key) {
|
||||
return types.get(key);
|
||||
}
|
||||
|
||||
@PublicApi(exclude = true)
|
||||
public enum StoredType {
|
||||
Asset(ASSET_TYPE_CODE), Boolean(BOOLEAN_TYPE_CODE), Byte(BYTE_TYPE_CODE),
|
||||
ByteArray(BYTE_ARRAY_TYPE_CODE), DataMap(DATAMAP_TYPE_CODE), DataMapArrayList(DataMap),
|
||||
Double(DOUBLE_TYPE_CODE), Float(FLOAT_TYPE_CODE), FloatArray(FLOAT_ARRAY_TYPE_CODE),
|
||||
Integer(INTEGER_TYPE_CODE), IntegerArrayList(Integer), Long(LONG_TYPE_CODE),
|
||||
LongArray(LONG_ARRAY_TYPE_CODE), String(STRING_TYPE_CODE),
|
||||
StringArray(STRING_ARRAY_TYPE_CODE), StringArrayList(String);
|
||||
|
||||
private int typeCode;
|
||||
private StoredType listType;
|
||||
|
||||
StoredType(int typeCode) {
|
||||
this.typeCode = typeCode;
|
||||
}
|
||||
|
||||
StoredType(StoredType listType) {
|
||||
this.typeCode = LIST_TYPE_CODE;
|
||||
this.listType = listType;
|
||||
}
|
||||
|
||||
public int getTypeCode() {
|
||||
return typeCode;
|
||||
}
|
||||
|
||||
public StoredType getListType() {
|
||||
return listType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a DataMap from a Bundle. The input Bundle is expected to contain only elements
|
||||
* supported by DataMap. Any elements in the Bundle not supported by DataMap will be dropped.
|
||||
@ -82,7 +133,46 @@ public class DataMap {
|
||||
DataMap res = new DataMap();
|
||||
if (bundle != null) {
|
||||
for (String key : bundle.keySet()) {
|
||||
res.data.put(key, bundle.get(key));
|
||||
Object val = bundle.get(key);
|
||||
if (val instanceof Asset) {
|
||||
res.putAsset(key, (Asset) val);
|
||||
} else if (val instanceof Boolean) {
|
||||
res.putBoolean(key, (Boolean) val);
|
||||
} else if (val instanceof Byte) {
|
||||
res.putByte(key, (Byte) val);
|
||||
} else if (val instanceof byte[]) {
|
||||
res.putByteArray(key, (byte[]) val);
|
||||
} else if (val instanceof Bundle) {
|
||||
res.putDataMap(key, DataMap.fromBundle((Bundle) val));
|
||||
} else if (val instanceof Double) {
|
||||
res.putDouble(key, (Double) val);
|
||||
} else if (val instanceof Float) {
|
||||
res.putFloat(key, (Float) val);
|
||||
} else if (val instanceof float[]) {
|
||||
res.putFloatArray(key, (float[]) val);
|
||||
} else if (val instanceof Integer) {
|
||||
res.putInt(key, (Integer) val);
|
||||
} else if (val instanceof Long) {
|
||||
res.putLong(key, (Long) val);
|
||||
} else if (val instanceof long[]) {
|
||||
res.putLongArray(key, (long[]) val);
|
||||
} else if (val instanceof String) {
|
||||
res.putString(key, (String) val);
|
||||
} else if (val instanceof String[]) {
|
||||
res.putStringArray(key, (String[]) val);
|
||||
} else if (val instanceof ArrayList) {
|
||||
if (((ArrayList) val).isEmpty() || ((ArrayList) val).get(0) instanceof String) {
|
||||
res.putStringArrayList(key, (ArrayList<String>) val);
|
||||
} else if (((ArrayList) val).get(0) instanceof Bundle) {
|
||||
ArrayList<DataMap> dataMaps = new ArrayList<DataMap>();
|
||||
for (Bundle b : ((ArrayList<Bundle>) val)) {
|
||||
dataMaps.add(DataMap.fromBundle(b));
|
||||
}
|
||||
res.putDataMapArrayList(key, dataMaps);
|
||||
} else if (((ArrayList) val).get(0) instanceof Integer) {
|
||||
res.putIntegerArrayList(key, (ArrayList<Integer>) val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
@ -92,7 +182,7 @@ public class DataMap {
|
||||
* @return a DataMap from a byte[].
|
||||
*/
|
||||
public static DataMap fromByteArray(byte[] bytes) {
|
||||
return null; // TODO
|
||||
return DataBundleUtil.readDataMap(bytes, Collections.<Asset>emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -213,6 +303,11 @@ public class DataMap {
|
||||
}
|
||||
}
|
||||
|
||||
public void putAsset(String key, Asset value) {
|
||||
data.put(key, value);
|
||||
types.put(key, StoredType.Asset);
|
||||
}
|
||||
|
||||
public void putBoolean(String key, boolean value) {
|
||||
data.put(key, value);
|
||||
types.put(key, StoredType.Boolean);
|
||||
@ -302,7 +397,7 @@ public class DataMap {
|
||||
for (String key : data.keySet()) {
|
||||
switch (types.get(key)) {
|
||||
case Asset:
|
||||
bundle.putParcelable(key, (Asset)data.get(key));
|
||||
bundle.putParcelable(key, (Asset) data.get(key));
|
||||
break;
|
||||
case Boolean:
|
||||
bundle.putBoolean(key, (Boolean) data.get(key));
|
||||
@ -317,7 +412,11 @@ public class DataMap {
|
||||
bundle.putBundle(key, ((DataMap) data.get(key)).toBundle());
|
||||
break;
|
||||
case DataMapArrayList:
|
||||
// TODO
|
||||
ArrayList<Bundle> bundles = new ArrayList<Bundle>();
|
||||
for (DataMap dataMap : ((ArrayList<DataMap>) data.get(key))) {
|
||||
bundles.add(dataMap.toBundle());
|
||||
}
|
||||
bundle.putParcelableArrayList(key, bundles);
|
||||
break;
|
||||
case Double:
|
||||
bundle.putDouble(key, (Double) data.get(key));
|
||||
@ -355,15 +454,10 @@ public class DataMap {
|
||||
}
|
||||
|
||||
public byte[] toByteArray() {
|
||||
return null; // TODO
|
||||
return DataBundleUtil.createBytes(this);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "DataMap{size=" + size() + "}";
|
||||
}
|
||||
|
||||
private enum StoredType {
|
||||
Asset, Boolean, Byte, ByteArray, DataMap, DataMapArrayList, Double, Float, FloatArray,
|
||||
Integer, IntegerArrayList, Long, LongArray, String, StringArray, StringArrayList
|
||||
}
|
||||
}
|
||||
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2015 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 com.google.android.gms.wearable;
|
||||
|
||||
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 com.google.android.gms.common.api.Status;
|
||||
|
||||
import org.microg.gms.common.PublicApi;
|
||||
|
||||
@PublicApi
|
||||
public interface MessageApi {
|
||||
|
||||
/**
|
||||
* A value returned by {@link SendMessageResult#getRequestId()} when
|
||||
* {@link #sendMessage(GoogleApiClient, String, String, byte[])} fails.
|
||||
*/
|
||||
int UNKNOWN_REQUEST_ID = -1;
|
||||
|
||||
/**
|
||||
* Registers a listener to be notified of received messages. Calls to this method should
|
||||
* balanced with {@link #removeListener(GoogleApiClient, MessageListener)} to avoid leaking
|
||||
* resources.
|
||||
* <p/>
|
||||
* Callers wishing to be notified of events in the background should use {@link WearableListenerService}.
|
||||
*/
|
||||
PendingResult<Status> addListener(GoogleApiClient client, MessageListener listener);
|
||||
|
||||
/**
|
||||
* Removes a message listener which was previously added through
|
||||
* {@link #addListener(GoogleApiClient, MessageListener)}.
|
||||
*/
|
||||
PendingResult<Status> removeListener(GoogleApiClient client, MessageListener listener);
|
||||
|
||||
/**
|
||||
* Sends {@code byte[]} data to the specified node.
|
||||
*
|
||||
* @param nodeId identifier for a particular node on the Android Wear network. Valid targets
|
||||
* may be obtained through {@link NodeApi#getConnectedNodes(GoogleApiClient)}
|
||||
* or from the host in {@link DataItem#getUri()}.
|
||||
* @param path identifier used to specify a particular endpoint at the receiving node
|
||||
* @param data small array of information to pass to the target node. Generally not larger
|
||||
* than 100k
|
||||
*/
|
||||
PendingResult<SendMessageResult> sendMessage(GoogleApiClient client, String nodeId,
|
||||
String path, byte[] data);
|
||||
|
||||
/**
|
||||
* Used with {@link MessageApi#addListener(GoogleApiClient, MessageListener)} to receive
|
||||
* message events.
|
||||
* <p/>
|
||||
* Callers wishing to be notified of events in the background should use
|
||||
* {@link WearableListenerService}.
|
||||
*/
|
||||
interface MessageListener {
|
||||
/**
|
||||
* Notification that a message has been received.
|
||||
*/
|
||||
void onMessageReceived(MessageEvent messageEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains the request id assigned to the message. On failure, the id will be
|
||||
* {@link MessageApi#UNKNOWN_REQUEST_ID} and the status will be unsuccessful.
|
||||
*/
|
||||
interface SendMessageResult extends Result {
|
||||
/**
|
||||
* @return an ID used to identify the sent message. If {@link #getStatus()} is not
|
||||
* successful, this value will be {@link MessageApi#UNKNOWN_REQUEST_ID}.
|
||||
*/
|
||||
int getRequestId();
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ package com.google.android.gms.wearable;
|
||||
import com.google.android.gms.common.api.Api;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
|
||||
import org.microg.gms.common.PublicApi;
|
||||
import org.microg.gms.wearable.DataApiImpl;
|
||||
import org.microg.gms.wearable.MessageApiImpl;
|
||||
import org.microg.gms.wearable.NodeApiImpl;
|
||||
@ -27,6 +28,7 @@ import org.microg.gms.wearable.WearableApiBuilder;
|
||||
/**
|
||||
* An API for the Android Wear platform.
|
||||
*/
|
||||
@PublicApi
|
||||
public class Wearable {
|
||||
/**
|
||||
* Token to pass to {@link GoogleApiClient.Builder#addApi(Api)} to enable the Wearable features.
|
||||
@ -38,6 +40,12 @@ public class Wearable {
|
||||
public static final NodeApi NodeApi = new NodeApiImpl();
|
||||
|
||||
public static class WearableOptions implements Api.ApiOptions.Optional {
|
||||
/**
|
||||
* Special option for microG to allow implementation of a FOSS first party Android Wear app
|
||||
*/
|
||||
@PublicApi(exclude = true)
|
||||
public boolean firstPartyMode = false;
|
||||
|
||||
public static class Builder {
|
||||
public WearableOptions build() {
|
||||
return new WearableOptions();
|
||||
|
@ -18,41 +18,251 @@ package com.google.android.gms.wearable;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.common.data.DataHolder;
|
||||
import com.google.android.gms.wearable.internal.AmsEntityUpdateParcelable;
|
||||
import com.google.android.gms.wearable.internal.AncsNotificationParcelable;
|
||||
import com.google.android.gms.wearable.internal.CapabilityInfoParcelable;
|
||||
import com.google.android.gms.wearable.internal.ChannelEventParcelable;
|
||||
import com.google.android.gms.wearable.internal.IWearableListener;
|
||||
import com.google.android.gms.wearable.internal.MessageEventParcelable;
|
||||
import com.google.android.gms.wearable.internal.NodeParcelable;
|
||||
|
||||
import org.microg.gms.common.PublicApi;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
|
||||
|
||||
@PublicApi
|
||||
public abstract class WearableListenerService extends Service implements CapabilityApi.CapabilityListener, ChannelApi.ChannelListener, DataApi.DataListener, MessageApi.MessageListener, NodeApi.NodeListener {
|
||||
private static final String BIND_LISTENER_INTENT_ACTION = "com.google.android.gms.wearable.BIND_LISTENER";
|
||||
private static final String TAG = "GmsWearListenerSvc";
|
||||
|
||||
private HandlerThread handlerThread;
|
||||
private IWearableListener listener;
|
||||
private ServiceHandler serviceHandler;
|
||||
private Object lock = new Object();
|
||||
private boolean disconnected = false;
|
||||
|
||||
public abstract class WearableListenerService extends Service implements DataApi.DataListener, MessageApi.MessageListener, NodeApi.NodeListener {
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (BIND_LISTENER_INTENT_ACTION.equals(intent.getAction())) {
|
||||
return listener.asBinder();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
|
||||
}
|
||||
|
||||
public void onConnectedNodes(List<Node> connectedNodes) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelClosed(Channel channel, int closeReason, int appSpecificErrorCode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelOpened(Channel channel) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
handlerThread = new HandlerThread("WearableListenerService");
|
||||
handlerThread.start();
|
||||
serviceHandler = new ServiceHandler(handlerThread.getLooper());
|
||||
listener = new Listener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataChanged(DataEventBuffer dataEvents) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
synchronized (lock) {
|
||||
if (serviceHandler == null) {
|
||||
throw new IllegalStateException("serviceHandler not set, did you override onCreate() but forget to call super.onCreate()?");
|
||||
}
|
||||
serviceHandler.getLooper().quit();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@PublicApi(exclude = true)
|
||||
public void onEntityUpdate(AmsEntityUpdate entityUpdate) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInputClosed(Channel channel, @ChannelApi.CloseReason int closeReason, int appSpecificErrorCode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(MessageEvent messageEvent) {
|
||||
}
|
||||
|
||||
@PublicApi(exclude = true)
|
||||
public void onNotificationReceived(AncsNotification notification) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOutputClosed(Channel channel, @ChannelApi.CloseReason int closeReason, int appSpecificErrorCode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerConnected(Node peer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerDisconnected(Node peer) {
|
||||
}
|
||||
|
||||
private class Listener extends IWearableListener.Stub {
|
||||
private int knownGoodUid = -1;
|
||||
|
||||
private boolean post(Runnable runnable) {
|
||||
int callingUid = Binder.getCallingUid();
|
||||
if (callingUid != knownGoodUid) {
|
||||
// TODO: Verify Gms is calling
|
||||
String[] packagesForUid = getPackageManager().getPackagesForUid(callingUid);
|
||||
if (packagesForUid != null) {
|
||||
if (Arrays.asList(packagesForUid).contains(GMS_PACKAGE_NAME)) {
|
||||
knownGoodUid = callingUid;
|
||||
} else {
|
||||
throw new SecurityException("Caller is not Services Core");
|
||||
}
|
||||
}
|
||||
}
|
||||
synchronized (lock) {
|
||||
if (disconnected) {
|
||||
return false;
|
||||
}
|
||||
serviceHandler.post(runnable);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataChanged(final DataHolder data) throws RemoteException {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
WearableListenerService.this.onDataChanged(new DataEventBuffer(data));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(final MessageEventParcelable messageEvent) throws RemoteException {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
WearableListenerService.this.onMessageReceived(messageEvent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerConnected(final NodeParcelable node) throws RemoteException {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
WearableListenerService.this.onPeerConnected(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerDisconnected(final NodeParcelable node) throws RemoteException {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
WearableListenerService.this.onPeerDisconnected(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectedNodes(final List<NodeParcelable> nodes) throws RemoteException {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
WearableListenerService.this.onConnectedNodes(new ArrayList<Node>(nodes));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectedCapabilityChanged(final CapabilityInfoParcelable capabilityInfo) throws RemoteException {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
WearableListenerService.this.onCapabilityChanged(capabilityInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationReceived(final AncsNotificationParcelable notification) throws RemoteException {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
WearableListenerService.this.onNotificationReceived(notification);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityUpdate(final AmsEntityUpdateParcelable update) throws RemoteException {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
WearableListenerService.this.onEntityUpdate(update);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelEvent(final ChannelEventParcelable channelEvent) throws RemoteException {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
switch (channelEvent.eventType) {
|
||||
case 1:
|
||||
WearableListenerService.this.onChannelOpened(channelEvent.channel);
|
||||
break;
|
||||
case 2:
|
||||
WearableListenerService.this.onChannelClosed(channelEvent.channel, channelEvent.closeReason, channelEvent.appSpecificErrorCode);
|
||||
break;
|
||||
case 3:
|
||||
WearableListenerService.this.onInputClosed(channelEvent.channel, channelEvent.closeReason, channelEvent.appSpecificErrorCode);
|
||||
break;
|
||||
case 4:
|
||||
WearableListenerService.this.onOutputClosed(channelEvent.channel, channelEvent.closeReason, channelEvent.appSpecificErrorCode);
|
||||
break;
|
||||
default:
|
||||
Log.w(TAG, "Unknown ChannelEvent.eventType");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class ServiceHandler extends Handler {
|
||||
public ServiceHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.wearable;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.common.api.Status;
|
||||
import com.google.android.gms.common.data.DataHolder;
|
||||
import com.google.android.gms.wearable.internal.DeleteDataItemsResponse;
|
||||
import com.google.android.gms.wearable.internal.GetCloudSyncSettingResponse;
|
||||
import com.google.android.gms.wearable.internal.GetConfigResponse;
|
||||
import com.google.android.gms.wearable.internal.GetConfigsResponse;
|
||||
import com.google.android.gms.wearable.internal.GetConnectedNodesResponse;
|
||||
import com.google.android.gms.wearable.internal.GetDataItemResponse;
|
||||
import com.google.android.gms.wearable.internal.GetFdForAssetResponse;
|
||||
import com.google.android.gms.wearable.internal.GetLocalNodeResponse;
|
||||
import com.google.android.gms.wearable.internal.IWearableCallbacks;
|
||||
import com.google.android.gms.wearable.internal.PutDataResponse;
|
||||
import com.google.android.gms.wearable.internal.SendMessageResponse;
|
||||
import com.google.android.gms.wearable.internal.StorageInfoResponse;
|
||||
|
||||
public class BaseWearableCallbacks extends IWearableCallbacks.Stub {
|
||||
private static final String TAG = "GmsWearBaseCallback";
|
||||
|
||||
@Override
|
||||
public void onGetConfigResponse(GetConfigResponse response) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onGetConfigResponse");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPutDataResponse(PutDataResponse response) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onPutDataResponse");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetDataItemResponse(GetDataItemResponse response) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onGetDataItemResponse");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataItemChanged(DataHolder dataHolder) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onDataItemChanged");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteDataItemsResponse(DeleteDataItemsResponse response) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onDeleteDataItemsResponse");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendMessageResponse(SendMessageResponse response) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onSendMessageResponse");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetFdForAssetResponse(GetFdForAssetResponse response) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onGetFdForAssetResponse");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetLocalNodeResponse(GetLocalNodeResponse response) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onGetLocalNodeResponse");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetConnectedNodesResponse(GetConnectedNodesResponse response) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onGetConnectedNodesResponse");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatus(Status status) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onStatus");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStorageInfoResponse(StorageInfoResponse response) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onStorageInfoResponse");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetConfigsResponse(GetConfigsResponse response) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onGetConfigsResponse");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetCloudSyncSettingResponse(GetCloudSyncSettingResponse response) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onGetCloudSyncSettingResponse");
|
||||
|
||||
}
|
||||
}
|
@ -30,46 +30,46 @@ import com.google.android.gms.wearable.internal.PutDataRequest;
|
||||
public class DataApiImpl implements DataApi {
|
||||
@Override
|
||||
public PendingResult<Status> addListener(GoogleApiClient client, DataListener listener) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<DeleteDataItemsResult> deleteDataItems(GoogleApiClient client, Uri uri) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<DataItemResult> getDataItem(GoogleApiClient client, Uri uri) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<DataItemBuffer> getDataItems(GoogleApiClient client) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<DataItemBuffer> getDataItems(GoogleApiClient client, Uri uri) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<GetFdForAssetResult> getFdForAsset(GoogleApiClient client, DataItemAsset asset) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<GetFdForAssetResult> getFdForAsset(GoogleApiClient client, Asset asset) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<DataItemResult> putDataItem(GoogleApiClient client, PutDataRequest request) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<Status> removeListener(GoogleApiClient client, DataListener listener) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
@ -16,24 +16,42 @@
|
||||
|
||||
package org.microg.gms.wearable;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.api.PendingResult;
|
||||
import com.google.android.gms.common.api.Status;
|
||||
import com.google.android.gms.wearable.MessageApi;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
import com.google.android.gms.wearable.internal.SendMessageResponse;
|
||||
|
||||
import org.microg.gms.common.GmsConnector;
|
||||
import org.microg.gms.common.api.ApiConnection;
|
||||
|
||||
public class MessageApiImpl implements MessageApi {
|
||||
@Override
|
||||
public PendingResult<Status> addListener(GoogleApiClient client, MessageListener listener) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<Status> removeListener(GoogleApiClient client, MessageListener listener) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<SendMessageResult> sendMessage(GoogleApiClient client, String nodeId, String path, byte[] data) {
|
||||
return null;
|
||||
public PendingResult<SendMessageResult> sendMessage(GoogleApiClient client, final String nodeId, final String path, final byte[] data) {
|
||||
return GmsConnector.call(client, Wearable.API, new GmsConnector.Callback<WearableClientImpl, SendMessageResult>() {
|
||||
@Override
|
||||
public void onClientAvailable(WearableClientImpl client, final ResultProvider<SendMessageResult> resultProvider) throws RemoteException {
|
||||
client.getServiceInterface().sendMessage(new BaseWearableCallbacks() {
|
||||
@Override
|
||||
public void onSendMessageResponse(SendMessageResponse response) throws RemoteException {
|
||||
resultProvider.onResultAvailable(response);
|
||||
}
|
||||
}, nodeId, path, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -24,21 +24,21 @@ import com.google.android.gms.wearable.NodeApi;
|
||||
public class NodeApiImpl implements NodeApi {
|
||||
@Override
|
||||
public PendingResult<Status> addListener(GoogleApiClient client, NodeListener listener) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<GetConnectedNodesResult> getConnectedNodes(GoogleApiClient client) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<GetLocalNodeResult> getLocalNode(GoogleApiClient client) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingResult<Status> removeListener(GoogleApiClient client, NodeListener listener) {
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ package org.microg.gms.wearable;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.common.api.AccountInfo;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
@ -34,7 +33,6 @@ public class WearableApiBuilder implements ApiBuilder<Wearable.WearableOptions>
|
||||
public ApiConnection build(Context context, Looper looper, Wearable.WearableOptions options,
|
||||
AccountInfo accountInfo, GoogleApiClient.ConnectionCallbacks callbacks,
|
||||
GoogleApiClient.OnConnectionFailedListener connectionFailedListener) {
|
||||
Log.d(TAG, "Wearables not supported");
|
||||
return null;
|
||||
return new WearableClientImpl(context, options, callbacks, connectionFailedListener);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.wearable;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
import com.google.android.gms.wearable.internal.IWearableService;
|
||||
|
||||
import org.microg.gms.common.GmsClient;
|
||||
import org.microg.gms.common.GmsService;
|
||||
import org.microg.gms.common.api.GoogleApiClientImpl;
|
||||
|
||||
public class WearableClientImpl extends GmsClient<IWearableService> {
|
||||
private static final String TAG = "GmsWearClient";
|
||||
|
||||
public WearableClientImpl(Context context, Wearable.WearableOptions options, GoogleApiClient.ConnectionCallbacks callbacks, GoogleApiClient.OnConnectionFailedListener connectionFailedListener) {
|
||||
super(context, callbacks, connectionFailedListener, GmsService.WEARABLE.ACTION);
|
||||
serviceId = GmsService.WEARABLE.SERVICE_ID;
|
||||
if (options != null && options.firstPartyMode)
|
||||
extras.putBoolean("firstPartyMode", true);
|
||||
Log.d(TAG, "<init>");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IWearableService interfaceFromBinder(IBinder binder) {
|
||||
return IWearableService.Stub.asInterface(binder);
|
||||
}
|
||||
|
||||
public static WearableClientImpl get(GoogleApiClient apiClient) {
|
||||
if (apiClient instanceof GoogleApiClientImpl) {
|
||||
return (WearableClientImpl) ((GoogleApiClientImpl) apiClient).getApiConnection(Wearable.API);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,658 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.wearable.databundle;
|
||||
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.google.android.gms.wearable.Asset;
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
import com.squareup.wire.Wire;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
public class DataBundleUtil {
|
||||
|
||||
public static DataMap readDataMap(byte[] bytes, List<Asset> assets) {
|
||||
try {
|
||||
return readDataMap(new Wire().parseFrom(bytes, DataBundle.class), assets);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static DataMap readDataMap(DataBundle dataBundle, List<Asset> assets) {
|
||||
return readDataMap(dataBundle.entries, assets);
|
||||
}
|
||||
|
||||
public static DataMap readDataMap(List<DataBundleEntry> entries, List<Asset> assets) {
|
||||
DataMap dataMap = new DataMap();
|
||||
for (DataBundleEntry entry : entries) {
|
||||
readAndStore(dataMap, entry.key, entry.typedValue, assets);
|
||||
}
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
public static byte[] createBytes(DataMap dataMap) {
|
||||
AssetAnnotatedDataBundle dataBundle = createDataBundle(dataMap);
|
||||
if (!dataBundle.getAssets().isEmpty()) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
return dataBundle.getData();
|
||||
}
|
||||
|
||||
public static AssetAnnotatedDataBundle createDataBundle(DataMap dataMap) {
|
||||
AssetAnnotatedDataBundle dataBundle = new AssetAnnotatedDataBundle();
|
||||
dataBundle.assets = new ArrayList<Asset>();
|
||||
dataBundle.dataBundle = new DataBundle(createEntryList(dataMap, dataBundle.assets));
|
||||
return dataBundle;
|
||||
}
|
||||
|
||||
private static List<DataBundleEntry> createEntryList(DataMap dataMap, List<Asset> assets) {
|
||||
List<DataBundleEntry> entries = new ArrayList<DataBundleEntry>();
|
||||
for (String key : dataMap.keySet()) {
|
||||
entries.add(getTypeHelper(dataMap.getType(key)).loadAndCreateEntry(dataMap, key, assets));
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static void readAndStore(DataMap dataMap, String key, DataBundleTypedValue value, List<Asset> assets) {
|
||||
if (value.type == null) return;
|
||||
getTypeHelper(value.type).readAndStore(dataMap, key, value, assets);
|
||||
}
|
||||
|
||||
|
||||
private static SparseArray<TypeHelper> typeHelperByCode;
|
||||
|
||||
private static void rememberTypeReader(TypeHelper typeHelper) {
|
||||
typeHelperByCode.put(typeHelper.type, typeHelper);
|
||||
}
|
||||
|
||||
static TypeHelper getTypeHelper(int type) {
|
||||
if (typeHelperByCode.get(type) != null) {
|
||||
return typeHelperByCode.get(type);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
static TypeHelper getTypeHelper(DataMap.StoredType type) {
|
||||
return getTypeHelper(type.getTypeCode());
|
||||
}
|
||||
|
||||
static TypeHelper getListInnerTypeHelper(DataMap.StoredType type) {
|
||||
return getTypeHelper(type.getListType());
|
||||
}
|
||||
|
||||
public static final int BYTE_ARRAY_TYPE_CODE = 1;
|
||||
static TypeHelper<byte[]> BYTEARRAY = new TypeHelper<byte[]>(BYTE_ARRAY_TYPE_CODE) {
|
||||
@Override
|
||||
byte[] read(DataBundleValue value, List<Asset> assets) {
|
||||
return value.byteArray.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(byte[] value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().byteArray(ByteString.of(value)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, byte[] value) {
|
||||
dataMap.putByteArray(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
byte[] load(DataMap dataMap, String key) {
|
||||
return dataMap.getByteArray(key);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int STRING_TYPE_CODE = 2;
|
||||
static TypeHelper<String> STRING = new TypeHelper<String>(STRING_TYPE_CODE) {
|
||||
@Override
|
||||
String read(DataBundleValue value, List<Asset> assets) {
|
||||
return value.stringVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(String value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().stringVal(value).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, String value) {
|
||||
dataMap.putString(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
void storeList(DataMap dataMap, String key, ArrayList<String> valueList) {
|
||||
dataMap.putStringArrayList(key, valueList);
|
||||
}
|
||||
|
||||
@Override
|
||||
String load(DataMap dataMap, String key) {
|
||||
return dataMap.getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
AnnotatedArrayList<String> loadList(DataMap dataMap, String key) {
|
||||
AnnotatedArrayList<String> list = new AnnotatedArrayList<String>(this);
|
||||
list.addAll(dataMap.getStringArrayList(key));
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
public static final int DOUBLE_TYPE_CODE = 3;
|
||||
static TypeHelper<Double> DOUBLE = new TypeHelper<Double>(DOUBLE_TYPE_CODE) {
|
||||
@Override
|
||||
Double read(DataBundleValue value, List<Asset> assets) {
|
||||
return value.doubleVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(Double value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().doubleVal(value).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, Double value) {
|
||||
dataMap.putDouble(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
Double load(DataMap dataMap, String key) {
|
||||
return dataMap.getDouble(key);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int FLOAT_TYPE_CODE = 4;
|
||||
static TypeHelper<Float> FLOAT = new TypeHelper<Float>(FLOAT_TYPE_CODE) {
|
||||
@Override
|
||||
Float read(DataBundleValue value, List<Asset> assets) {
|
||||
return value.floatVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(Float value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().floatVal(value).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, Float value) {
|
||||
dataMap.putFloat(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
Float load(DataMap dataMap, String key) {
|
||||
return dataMap.getFloat(key);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int LONG_TYPE_CODE = 5;
|
||||
static TypeHelper<Long> LONG = new TypeHelper<Long>(LONG_TYPE_CODE) {
|
||||
@Override
|
||||
Long read(DataBundleValue value, List<Asset> assets) {
|
||||
return value.longVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(Long value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().longVal(value).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, Long value) {
|
||||
dataMap.putLong(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
Long load(DataMap dataMap, String key) {
|
||||
return dataMap.getLong(key);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int INTEGER_TYPE_CODE = 6;
|
||||
static TypeHelper<Integer> INTEGER = new TypeHelper<Integer>(INTEGER_TYPE_CODE) {
|
||||
@Override
|
||||
Integer read(DataBundleValue value, List<Asset> assets) {
|
||||
return value.intVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(Integer value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().intVal(value).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, Integer value) {
|
||||
dataMap.putInt(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
void storeList(DataMap dataMap, String key, ArrayList<Integer> valueList) {
|
||||
dataMap.putIntegerArrayList(key, valueList);
|
||||
}
|
||||
|
||||
@Override
|
||||
Integer load(DataMap dataMap, String key) {
|
||||
return dataMap.getInt(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
AnnotatedArrayList<Integer> loadList(DataMap dataMap, String key) {
|
||||
AnnotatedArrayList<Integer> list = new AnnotatedArrayList<Integer>(this);
|
||||
list.addAll(dataMap.getIntegerArrayList(key));
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
public static final int BYTE_TYPE_CODE = 7;
|
||||
static TypeHelper<Byte> BYTE = new TypeHelper<Byte>(BYTE_TYPE_CODE) {
|
||||
@Override
|
||||
Byte read(DataBundleValue value, List<Asset> assets) {
|
||||
return (byte) (int) value.byteVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(Byte value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().byteVal((int) (byte) value).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, Byte value) {
|
||||
dataMap.putByte(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
Byte load(DataMap dataMap, String key) {
|
||||
return dataMap.getByte(key);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int BOOLEAN_TYPE_CODE = 8;
|
||||
static TypeHelper<Boolean> BOOLEAN = new TypeHelper<Boolean>(BOOLEAN_TYPE_CODE) {
|
||||
@Override
|
||||
Boolean read(DataBundleValue value, List<Asset> assets) {
|
||||
return value.booleanVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(Boolean value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().booleanVal(value).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, Boolean value) {
|
||||
dataMap.putBoolean(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
Boolean load(DataMap dataMap, String key) {
|
||||
return dataMap.getBoolean(key);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int DATAMAP_TYPE_CODE = 9;
|
||||
static TypeHelper<DataMap> DATAMAP = new TypeHelper<DataMap>(DATAMAP_TYPE_CODE) {
|
||||
@Override
|
||||
DataMap read(DataBundleValue value, List<Asset> assets) {
|
||||
return readDataMap(value.map, assets);
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(DataMap value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().map(createEntryList(value, assets)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, DataMap value) {
|
||||
dataMap.putDataMap(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
void storeList(DataMap dataMap, String key, ArrayList<DataMap> valueList) {
|
||||
dataMap.putDataMapArrayList(key, valueList);
|
||||
}
|
||||
|
||||
@Override
|
||||
DataMap load(DataMap dataMap, String key) {
|
||||
return dataMap.getDataMap(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
AnnotatedArrayList<DataMap> loadList(DataMap dataMap, String key) {
|
||||
AnnotatedArrayList<DataMap> list = new AnnotatedArrayList<DataMap>(this);
|
||||
list.addAll(dataMap.getDataMapArrayList(key));
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
public static final int LIST_TYPE_CODE = 10;
|
||||
static TypeHelper<AnnotatedArrayList<?>> ARRAYLIST = new TypeHelper<AnnotatedArrayList<?>>(LIST_TYPE_CODE) {
|
||||
@Override
|
||||
AnnotatedArrayList read(DataBundleValue value, List<Asset> assets) {
|
||||
TypeHelper innerTypeHelper = NULL;
|
||||
for (DataBundleTypedValue typedValue : value.list) {
|
||||
if (innerTypeHelper == NULL) {
|
||||
innerTypeHelper = getTypeHelper(typedValue.type);
|
||||
} else if (typedValue.type != innerTypeHelper.type && typedValue.type != NULL.type) {
|
||||
throw new IllegalArgumentException("List has elements of different types: " + innerTypeHelper.type + " and " + typedValue.type);
|
||||
}
|
||||
}
|
||||
return innerTypeHelper.readList(value.list, assets);
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(AnnotatedArrayList<?> value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().list(value.createList(assets)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, AnnotatedArrayList value) {
|
||||
value.store(dataMap, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
AnnotatedArrayList load(DataMap dataMap, String key) {
|
||||
return getListInnerTypeHelper(dataMap.getType(key)).loadList(dataMap, key);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int STRING_ARRAY_TYPE_CODE = 11;
|
||||
static TypeHelper<String[]> STRINGARRAY = new TypeHelper<String[]>(STRING_ARRAY_TYPE_CODE) {
|
||||
@Override
|
||||
String[] read(DataBundleValue value, List<Asset> assets) {
|
||||
return value.stringArray.toArray(new String[value.stringArray.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(String[] value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().stringArray(Arrays.asList(value)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, String[] value) {
|
||||
dataMap.putStringArray(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
String[] load(DataMap dataMap, String key) {
|
||||
return dataMap.getStringArray(key);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int LONG_ARRAY_TYPE_CODE = 12;
|
||||
static TypeHelper<long[]> LONGARRAY = new TypeHelper<long[]>(LONG_ARRAY_TYPE_CODE) {
|
||||
@Override
|
||||
long[] read(DataBundleValue value, List<Asset> assets) {
|
||||
long[] longArr = new long[value.longArray.size()];
|
||||
for (int i = 0; i < value.longArray.size(); i++) {
|
||||
longArr[i] = value.longArray.get(i);
|
||||
}
|
||||
return longArr;
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(long[] value, List<Asset> assets) {
|
||||
List<Long> longList = new ArrayList<Long>(value.length);
|
||||
for (long l : value) {
|
||||
longList.add(l);
|
||||
}
|
||||
return new DataBundleValue.Builder().longArray(longList).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, long[] value) {
|
||||
dataMap.putLongArray(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
long[] load(DataMap dataMap, String key) {
|
||||
return dataMap.getLongArray(key);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int ASSET_TYPE_CODE = 13;
|
||||
static TypeHelper<Asset> ASSET = new TypeHelper<Asset>(ASSET_TYPE_CODE) {
|
||||
@Override
|
||||
Asset read(DataBundleValue value, List<Asset> assets) {
|
||||
return assets.get(value.assetIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(Asset value, List<Asset> assets) {
|
||||
int index;
|
||||
if (assets.contains(value)) {
|
||||
index = assets.indexOf(value);
|
||||
} else {
|
||||
index = assets.size();
|
||||
assets.add(value);
|
||||
}
|
||||
return new DataBundleValue.Builder().assetIndex(index).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, Asset value) {
|
||||
dataMap.putAsset(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
Asset load(DataMap dataMap, String key) {
|
||||
return dataMap.getAsset(key);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int NULL_TYPE_CODE = 14;
|
||||
static TypeHelper<String> NULL = new TypeHelper<String>(NULL_TYPE_CODE) {
|
||||
@Override
|
||||
String read(DataBundleValue value, List<Asset> assets) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(String value, List<Asset> assets) {
|
||||
return new DataBundleValue.Builder().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, String value) {
|
||||
dataMap.putString(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
void storeList(DataMap dataMap, String key, ArrayList<String> valueList) {
|
||||
dataMap.putStringArrayList(key, valueList);
|
||||
}
|
||||
|
||||
@Override
|
||||
String load(DataMap dataMap, String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
AnnotatedArrayList<String> loadList(DataMap dataMap, String key) {
|
||||
AnnotatedArrayList<String> list = new AnnotatedArrayList<String>(this);
|
||||
list.addAll(dataMap.getStringArrayList(key));
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
public static final int FLOAT_ARRAY_TYPE_CODE = 15;
|
||||
static TypeHelper<float[]> FLOATARRAY = new TypeHelper<float[]>(FLOAT_ARRAY_TYPE_CODE) {
|
||||
@Override
|
||||
float[] read(DataBundleValue value, List<Asset> assets) {
|
||||
float[] floatArr = new float[value.floatArray.size()];
|
||||
for (int i = 0; i < value.floatArray.size(); i++) {
|
||||
floatArr[i] = value.floatArray.get(i);
|
||||
}
|
||||
return floatArr;
|
||||
}
|
||||
|
||||
@Override
|
||||
DataBundleValue create(float[] value, List<Asset> assets) {
|
||||
List<Float> floatList = new ArrayList<Float>(value.length);
|
||||
for (float f : value) {
|
||||
floatList.add(f);
|
||||
}
|
||||
return new DataBundleValue.Builder().floatArray(floatList).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
void store(DataMap dataMap, String key, float[] value) {
|
||||
dataMap.putFloatArray(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
float[] load(DataMap dataMap, String key) {
|
||||
return dataMap.getFloatArray(key);
|
||||
}
|
||||
};
|
||||
|
||||
static {
|
||||
typeHelperByCode = new SparseArray<TypeHelper>();
|
||||
rememberTypeReader(BYTEARRAY);
|
||||
rememberTypeReader(STRING);
|
||||
rememberTypeReader(DOUBLE);
|
||||
rememberTypeReader(FLOAT);
|
||||
rememberTypeReader(LONG);
|
||||
rememberTypeReader(INTEGER);
|
||||
rememberTypeReader(BYTE);
|
||||
rememberTypeReader(BOOLEAN);
|
||||
rememberTypeReader(DATAMAP);
|
||||
rememberTypeReader(ARRAYLIST);
|
||||
rememberTypeReader(STRINGARRAY);
|
||||
rememberTypeReader(LONGARRAY);
|
||||
rememberTypeReader(ASSET);
|
||||
rememberTypeReader(NULL);
|
||||
rememberTypeReader(FLOATARRAY);
|
||||
}
|
||||
|
||||
static class AssetAnnotatedDataBundle {
|
||||
private DataBundle dataBundle;
|
||||
private List<Asset> assets;
|
||||
|
||||
public List<Asset> getAssets() {
|
||||
return assets;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return dataBundle.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
static class AnnotatedArrayList<T> extends ArrayList<T> {
|
||||
private TypeHelper<T> innerType;
|
||||
|
||||
public AnnotatedArrayList(TypeHelper<T> innerType) {
|
||||
this.innerType = innerType;
|
||||
}
|
||||
|
||||
void store(DataMap dataMap, String key) {
|
||||
innerType.storeList(dataMap, key, this);
|
||||
}
|
||||
|
||||
public List<DataBundleTypedValue> createList(List<Asset> assets) {
|
||||
return innerType.createList(this, assets);
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class TypeHelper<T> {
|
||||
private int type;
|
||||
|
||||
public TypeHelper(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
abstract T read(DataBundleValue value, List<Asset> assets);
|
||||
|
||||
abstract DataBundleValue create(T value, List<Asset> assets);
|
||||
|
||||
T read(DataBundleTypedValue value, List<Asset> assets) {
|
||||
if (value.type == NULL_TYPE_CODE) {
|
||||
return null;
|
||||
} else if (value.type == type) {
|
||||
return read(value.value, assets);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
abstract void store(DataMap dataMap, String key, T value);
|
||||
|
||||
void storeList(DataMap dataMap, String key, ArrayList<T> valueList) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
abstract T load(DataMap dataMap, String key);
|
||||
|
||||
AnnotatedArrayList<T> loadList(DataMap dataMap, String key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
void readAndStore(DataMap dataMap, String key, DataBundleValue value, List<Asset> assets) {
|
||||
store(dataMap, key, read(value, assets));
|
||||
}
|
||||
|
||||
void readAndStore(DataMap dataMap, String key, DataBundleTypedValue value, List<Asset> assets) {
|
||||
store(dataMap, key, read(value, assets));
|
||||
}
|
||||
|
||||
void readAndStore(DataMap dataMap, DataBundleEntry entry, List<Asset> assets) {
|
||||
readAndStore(dataMap, entry.key, entry.typedValue, assets);
|
||||
}
|
||||
|
||||
AnnotatedArrayList<T> readList(List<DataBundleTypedValue> values, List<Asset> assets) {
|
||||
AnnotatedArrayList<T> list = new AnnotatedArrayList<T>(this);
|
||||
for (DataBundleTypedValue value : values) {
|
||||
list.add(read(value, assets));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
List<DataBundleTypedValue> createList(AnnotatedArrayList<T> value, List<Asset> assets) {
|
||||
List<DataBundleTypedValue> list = new ArrayList<DataBundleTypedValue>();
|
||||
for (T val : value) {
|
||||
list.add(createTyped(val, assets));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
void readAndStore(DataMap dataMap, String key, List<DataBundleTypedValue> values, List<Asset> assets) {
|
||||
storeList(dataMap, key, readList(values, assets));
|
||||
}
|
||||
|
||||
DataBundleTypedValue createTyped(T value, List<Asset> assets) {
|
||||
return new DataBundleTypedValue(type, create(value, assets));
|
||||
}
|
||||
|
||||
DataBundleValue loadAndCreate(DataMap dataMap, String key, List<Asset> assets) {
|
||||
return create(load(dataMap, key), assets);
|
||||
}
|
||||
|
||||
DataBundleTypedValue loadAndCreateTyped(DataMap dataMap, String key, List<Asset> assets) {
|
||||
return createTyped(load(dataMap, key), assets);
|
||||
}
|
||||
|
||||
DataBundleEntry loadAndCreateEntry(DataMap dataMap, String key, List<Asset> assets) {
|
||||
return new DataBundleEntry(key, loadAndCreateTyped(dataMap, key, assets));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
// Code generated by Wire protocol buffer compiler, do not edit.
|
||||
// Source file: protos-repo/databundle.proto
|
||||
package org.microg.gms.wearable.databundle;
|
||||
|
||||
import com.squareup.wire.Message;
|
||||
import com.squareup.wire.ProtoField;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.squareup.wire.Message.Label.REPEATED;
|
||||
|
||||
public final class DataBundle extends Message {
|
||||
|
||||
public static final List<DataBundleEntry> DEFAULT_ENTRIES = Collections.emptyList();
|
||||
|
||||
@ProtoField(tag = 1, label = REPEATED, messageType = DataBundleEntry.class)
|
||||
public final List<DataBundleEntry> entries;
|
||||
|
||||
public DataBundle(List<DataBundleEntry> entries) {
|
||||
this.entries = immutableCopyOf(entries);
|
||||
}
|
||||
|
||||
private DataBundle(Builder builder) {
|
||||
this(builder.entries);
|
||||
setBuilder(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) return true;
|
||||
if (!(other instanceof DataBundle)) return false;
|
||||
return equals(entries, ((DataBundle) other).entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = hashCode;
|
||||
return result != 0 ? result : (hashCode = entries != null ? entries.hashCode() : 1);
|
||||
}
|
||||
|
||||
public static final class Builder extends Message.Builder<DataBundle> {
|
||||
|
||||
public List<DataBundleEntry> entries;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(DataBundle message) {
|
||||
super(message);
|
||||
if (message == null) return;
|
||||
this.entries = copyOf(message.entries);
|
||||
}
|
||||
|
||||
public Builder entries(List<DataBundleEntry> entries) {
|
||||
this.entries = checkForNulls(entries);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataBundle build() {
|
||||
return new DataBundle(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
// Code generated by Wire protocol buffer compiler, do not edit.
|
||||
// Source file: protos-repo/databundle.proto
|
||||
package org.microg.gms.wearable.databundle;
|
||||
|
||||
import com.squareup.wire.Message;
|
||||
import com.squareup.wire.ProtoField;
|
||||
|
||||
import static com.squareup.wire.Message.Datatype.STRING;
|
||||
|
||||
public final class DataBundleEntry extends Message {
|
||||
|
||||
public static final String DEFAULT_KEY = "";
|
||||
|
||||
@ProtoField(tag = 1, type = STRING)
|
||||
public final String key;
|
||||
|
||||
@ProtoField(tag = 2)
|
||||
public final DataBundleTypedValue typedValue;
|
||||
|
||||
public DataBundleEntry(String key, DataBundleTypedValue typedValue) {
|
||||
this.key = key;
|
||||
this.typedValue = typedValue;
|
||||
}
|
||||
|
||||
private DataBundleEntry(Builder builder) {
|
||||
this(builder.key, builder.typedValue);
|
||||
setBuilder(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) return true;
|
||||
if (!(other instanceof DataBundleEntry)) return false;
|
||||
DataBundleEntry o = (DataBundleEntry) other;
|
||||
return equals(key, o.key)
|
||||
&& equals(typedValue, o.typedValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = hashCode;
|
||||
if (result == 0) {
|
||||
result = key != null ? key.hashCode() : 0;
|
||||
result = result * 37 + (typedValue != null ? typedValue.hashCode() : 0);
|
||||
hashCode = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final class Builder extends Message.Builder<DataBundleEntry> {
|
||||
|
||||
public String key;
|
||||
public DataBundleTypedValue typedValue;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(DataBundleEntry message) {
|
||||
super(message);
|
||||
if (message == null) return;
|
||||
this.key = message.key;
|
||||
this.typedValue = message.typedValue;
|
||||
}
|
||||
|
||||
public Builder key(String key) {
|
||||
this.key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder typedValue(DataBundleTypedValue typedValue) {
|
||||
this.typedValue = typedValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataBundleEntry build() {
|
||||
return new DataBundleEntry(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
// Code generated by Wire protocol buffer compiler, do not edit.
|
||||
// Source file: protos-repo/databundle.proto
|
||||
package org.microg.gms.wearable.databundle;
|
||||
|
||||
import com.squareup.wire.Message;
|
||||
import com.squareup.wire.ProtoField;
|
||||
|
||||
import static com.squareup.wire.Message.Datatype.INT32;
|
||||
|
||||
public final class DataBundleTypedValue extends Message {
|
||||
|
||||
public static final Integer DEFAULT_TYPE = 0;
|
||||
|
||||
@ProtoField(tag = 1, type = INT32)
|
||||
public final Integer type;
|
||||
|
||||
@ProtoField(tag = 2)
|
||||
public final DataBundleValue value;
|
||||
|
||||
public DataBundleTypedValue(Integer type, DataBundleValue value) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private DataBundleTypedValue(Builder builder) {
|
||||
this(builder.type, builder.value);
|
||||
setBuilder(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) return true;
|
||||
if (!(other instanceof DataBundleTypedValue)) return false;
|
||||
DataBundleTypedValue o = (DataBundleTypedValue) other;
|
||||
return equals(type, o.type)
|
||||
&& equals(value, o.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = hashCode;
|
||||
if (result == 0) {
|
||||
result = type != null ? type.hashCode() : 0;
|
||||
result = result * 37 + (value != null ? value.hashCode() : 0);
|
||||
hashCode = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final class Builder extends Message.Builder<DataBundleTypedValue> {
|
||||
|
||||
public Integer type;
|
||||
public DataBundleValue value;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(DataBundleTypedValue message) {
|
||||
super(message);
|
||||
if (message == null) return;
|
||||
this.type = message.type;
|
||||
this.value = message.value;
|
||||
}
|
||||
|
||||
public Builder type(Integer type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder value(DataBundleValue value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataBundleTypedValue build() {
|
||||
return new DataBundleTypedValue(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,259 @@
|
||||
// Code generated by Wire protocol buffer compiler, do not edit.
|
||||
// Source file: protos-repo/databundle.proto
|
||||
package org.microg.gms.wearable.databundle;
|
||||
|
||||
import com.squareup.wire.Message;
|
||||
import com.squareup.wire.ProtoField;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import okio.ByteString;
|
||||
|
||||
import static com.squareup.wire.Message.Datatype.BOOL;
|
||||
import static com.squareup.wire.Message.Datatype.BYTES;
|
||||
import static com.squareup.wire.Message.Datatype.DOUBLE;
|
||||
import static com.squareup.wire.Message.Datatype.FLOAT;
|
||||
import static com.squareup.wire.Message.Datatype.INT32;
|
||||
import static com.squareup.wire.Message.Datatype.INT64;
|
||||
import static com.squareup.wire.Message.Datatype.STRING;
|
||||
import static com.squareup.wire.Message.Label.REPEATED;
|
||||
|
||||
public final class DataBundleValue extends Message {
|
||||
|
||||
public static final ByteString DEFAULT_BYTEARRAY = ByteString.EMPTY;
|
||||
public static final String DEFAULT_STRINGVAL = "";
|
||||
public static final Double DEFAULT_DOUBLEVAL = 0D;
|
||||
public static final Float DEFAULT_FLOATVAL = 0F;
|
||||
public static final Long DEFAULT_LONGVAL = 0L;
|
||||
public static final Integer DEFAULT_INTVAL = 0;
|
||||
public static final Integer DEFAULT_BYTEVAL = 0;
|
||||
public static final Boolean DEFAULT_BOOLEANVAL = false;
|
||||
public static final List<DataBundleEntry> DEFAULT_MAP = Collections.emptyList();
|
||||
public static final List<DataBundleTypedValue> DEFAULT_LIST = Collections.emptyList();
|
||||
public static final List<String> DEFAULT_STRINGARRAY = Collections.emptyList();
|
||||
public static final List<Long> DEFAULT_LONGARRAY = Collections.emptyList();
|
||||
public static final Integer DEFAULT_ASSETINDEX = 0;
|
||||
public static final List<Float> DEFAULT_FLOATARRAY = Collections.emptyList();
|
||||
|
||||
@ProtoField(tag = 1, type = BYTES)
|
||||
public final ByteString byteArray;
|
||||
|
||||
@ProtoField(tag = 2, type = STRING)
|
||||
public final String stringVal;
|
||||
|
||||
@ProtoField(tag = 3, type = DOUBLE)
|
||||
public final Double doubleVal;
|
||||
|
||||
@ProtoField(tag = 4, type = FLOAT)
|
||||
public final Float floatVal;
|
||||
|
||||
@ProtoField(tag = 5, type = INT64)
|
||||
public final Long longVal;
|
||||
|
||||
@ProtoField(tag = 6, type = INT32)
|
||||
public final Integer intVal;
|
||||
|
||||
@ProtoField(tag = 7, type = INT32)
|
||||
public final Integer byteVal;
|
||||
|
||||
@ProtoField(tag = 8, type = BOOL)
|
||||
public final Boolean booleanVal;
|
||||
|
||||
@ProtoField(tag = 9, label = REPEATED, messageType = DataBundleEntry.class)
|
||||
public final List<DataBundleEntry> map;
|
||||
|
||||
@ProtoField(tag = 10, label = REPEATED, messageType = DataBundleTypedValue.class)
|
||||
public final List<DataBundleTypedValue> list;
|
||||
|
||||
@ProtoField(tag = 11, type = STRING, label = REPEATED)
|
||||
public final List<String> stringArray;
|
||||
|
||||
@ProtoField(tag = 12, type = INT64, label = REPEATED)
|
||||
public final List<Long> longArray;
|
||||
|
||||
@ProtoField(tag = 13, type = INT32)
|
||||
public final Integer assetIndex;
|
||||
|
||||
@ProtoField(tag = 14, type = FLOAT, label = REPEATED)
|
||||
public final List<Float> floatArray;
|
||||
|
||||
public DataBundleValue(ByteString byteArray, String stringVal, Double doubleVal, Float floatVal, Long longVal, Integer intVal, Integer byteVal, Boolean booleanVal, List<DataBundleEntry> map, List<DataBundleTypedValue> list, List<String> stringArray, List<Long> longArray, Integer assetIndex, List<Float> floatArray) {
|
||||
this.byteArray = byteArray;
|
||||
this.stringVal = stringVal;
|
||||
this.doubleVal = doubleVal;
|
||||
this.floatVal = floatVal;
|
||||
this.longVal = longVal;
|
||||
this.intVal = intVal;
|
||||
this.byteVal = byteVal;
|
||||
this.booleanVal = booleanVal;
|
||||
this.map = immutableCopyOf(map);
|
||||
this.list = immutableCopyOf(list);
|
||||
this.stringArray = immutableCopyOf(stringArray);
|
||||
this.longArray = immutableCopyOf(longArray);
|
||||
this.assetIndex = assetIndex;
|
||||
this.floatArray = immutableCopyOf(floatArray);
|
||||
}
|
||||
|
||||
private DataBundleValue(Builder builder) {
|
||||
this(builder.byteArray, builder.stringVal, builder.doubleVal, builder.floatVal, builder.longVal, builder.intVal, builder.byteVal, builder.booleanVal, builder.map, builder.list, builder.stringArray, builder.longArray, builder.assetIndex, builder.floatArray);
|
||||
setBuilder(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) return true;
|
||||
if (!(other instanceof DataBundleValue)) return false;
|
||||
DataBundleValue o = (DataBundleValue) other;
|
||||
return equals(byteArray, o.byteArray)
|
||||
&& equals(stringVal, o.stringVal)
|
||||
&& equals(doubleVal, o.doubleVal)
|
||||
&& equals(floatVal, o.floatVal)
|
||||
&& equals(longVal, o.longVal)
|
||||
&& equals(intVal, o.intVal)
|
||||
&& equals(byteVal, o.byteVal)
|
||||
&& equals(booleanVal, o.booleanVal)
|
||||
&& equals(map, o.map)
|
||||
&& equals(list, o.list)
|
||||
&& equals(stringArray, o.stringArray)
|
||||
&& equals(longArray, o.longArray)
|
||||
&& equals(assetIndex, o.assetIndex)
|
||||
&& equals(floatArray, o.floatArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = hashCode;
|
||||
if (result == 0) {
|
||||
result = byteArray != null ? byteArray.hashCode() : 0;
|
||||
result = result * 37 + (stringVal != null ? stringVal.hashCode() : 0);
|
||||
result = result * 37 + (doubleVal != null ? doubleVal.hashCode() : 0);
|
||||
result = result * 37 + (floatVal != null ? floatVal.hashCode() : 0);
|
||||
result = result * 37 + (longVal != null ? longVal.hashCode() : 0);
|
||||
result = result * 37 + (intVal != null ? intVal.hashCode() : 0);
|
||||
result = result * 37 + (byteVal != null ? byteVal.hashCode() : 0);
|
||||
result = result * 37 + (booleanVal != null ? booleanVal.hashCode() : 0);
|
||||
result = result * 37 + (map != null ? map.hashCode() : 1);
|
||||
result = result * 37 + (list != null ? list.hashCode() : 1);
|
||||
result = result * 37 + (stringArray != null ? stringArray.hashCode() : 1);
|
||||
result = result * 37 + (longArray != null ? longArray.hashCode() : 1);
|
||||
result = result * 37 + (assetIndex != null ? assetIndex.hashCode() : 0);
|
||||
result = result * 37 + (floatArray != null ? floatArray.hashCode() : 1);
|
||||
hashCode = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final class Builder extends Message.Builder<DataBundleValue> {
|
||||
|
||||
public ByteString byteArray;
|
||||
public String stringVal;
|
||||
public Double doubleVal;
|
||||
public Float floatVal;
|
||||
public Long longVal;
|
||||
public Integer intVal;
|
||||
public Integer byteVal;
|
||||
public Boolean booleanVal;
|
||||
public List<DataBundleEntry> map;
|
||||
public List<DataBundleTypedValue> list;
|
||||
public List<String> stringArray;
|
||||
public List<Long> longArray;
|
||||
public Integer assetIndex;
|
||||
public List<Float> floatArray;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(DataBundleValue message) {
|
||||
super(message);
|
||||
if (message == null) return;
|
||||
this.byteArray = message.byteArray;
|
||||
this.stringVal = message.stringVal;
|
||||
this.doubleVal = message.doubleVal;
|
||||
this.floatVal = message.floatVal;
|
||||
this.longVal = message.longVal;
|
||||
this.intVal = message.intVal;
|
||||
this.byteVal = message.byteVal;
|
||||
this.booleanVal = message.booleanVal;
|
||||
this.map = copyOf(message.map);
|
||||
this.list = copyOf(message.list);
|
||||
this.stringArray = copyOf(message.stringArray);
|
||||
this.longArray = copyOf(message.longArray);
|
||||
this.assetIndex = message.assetIndex;
|
||||
this.floatArray = copyOf(message.floatArray);
|
||||
}
|
||||
|
||||
public Builder byteArray(ByteString byteArray) {
|
||||
this.byteArray = byteArray;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder stringVal(String stringVal) {
|
||||
this.stringVal = stringVal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder doubleVal(Double doubleVal) {
|
||||
this.doubleVal = doubleVal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder floatVal(Float floatVal) {
|
||||
this.floatVal = floatVal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder longVal(Long longVal) {
|
||||
this.longVal = longVal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder intVal(Integer intVal) {
|
||||
this.intVal = intVal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder byteVal(Integer byteVal) {
|
||||
this.byteVal = byteVal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder booleanVal(Boolean booleanVal) {
|
||||
this.booleanVal = booleanVal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder map(List<DataBundleEntry> map) {
|
||||
this.map = checkForNulls(map);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder list(List<DataBundleTypedValue> list) {
|
||||
this.list = checkForNulls(list);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder stringArray(List<String> stringArray) {
|
||||
this.stringArray = checkForNulls(stringArray);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder longArray(List<Long> longArray) {
|
||||
this.longArray = checkForNulls(longArray);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder assetIndex(Integer assetIndex) {
|
||||
this.assetIndex = assetIndex;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder floatArray(List<Float> floatArray) {
|
||||
this.floatArray = checkForNulls(floatArray);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataBundleValue build() {
|
||||
return new DataBundleValue(this);
|
||||
}
|
||||
}
|
||||
}
|
33
play-services-wearable/src/main/protos-repo/databundle.proto
Normal file
33
play-services-wearable/src/main/protos-repo/databundle.proto
Normal file
@ -0,0 +1,33 @@
|
||||
option java_package = "org.microg.gms.wearable.databundle";
|
||||
option java_outer_classname = "DataBundleProto";
|
||||
|
||||
message DataBundle {
|
||||
repeated DataBundleEntry entries = 1;
|
||||
}
|
||||
|
||||
message DataBundleEntry {
|
||||
optional string key = 1;
|
||||
optional DataBundleTypedValue typedValue = 2;
|
||||
}
|
||||
|
||||
message DataBundleTypedValue {
|
||||
optional int32 type = 1;
|
||||
optional DataBundleValue value = 2;
|
||||
}
|
||||
|
||||
message DataBundleValue {
|
||||
optional bytes byteArray = 1;
|
||||
optional string stringVal = 2;
|
||||
optional double doubleVal = 3;
|
||||
optional float floatVal = 4;
|
||||
optional int64 longVal = 5;
|
||||
optional int32 intVal = 6;
|
||||
optional int32 byteVal = 7;
|
||||
optional bool booleanVal = 8;
|
||||
repeated DataBundleEntry map = 9;
|
||||
repeated DataBundleTypedValue list = 10;
|
||||
repeated string stringArray = 11;
|
||||
repeated int64 longArray = 12;
|
||||
optional int32 assetIndex = 13;
|
||||
repeated float floatArray = 14;
|
||||
}
|
@ -16,8 +16,8 @@
|
||||
|
||||
include ':safe-parcel'
|
||||
|
||||
include ':play-services-basement'
|
||||
include ':play-services-cast-api'
|
||||
include ':play-services-common-api'
|
||||
include ':play-services-iid-api'
|
||||
include ':play-services-location-api'
|
||||
include ':play-services-wearable-api'
|
||||
|
Loading…
x
Reference in New Issue
Block a user