diff --git a/play-services-api/src/main/java/com/google/android/gms/auth/AccountChangeEvent.java b/play-services-api/src/main/java/com/google/android/gms/auth/AccountChangeEvent.java index d9a19568..c147bcac 100644 --- a/play-services-api/src/main/java/com/google/android/gms/auth/AccountChangeEvent.java +++ b/play-services-api/src/main/java/com/google/android/gms/auth/AccountChangeEvent.java @@ -18,6 +18,20 @@ package com.google.android.gms.auth; import org.microg.safeparcel.AutoSafeParcelable; +<<<<<<< HEAD:play-services-api/src/main/java/com/google/android/gms/auth/AccountChangeEvent.java public class AccountChangeEvent extends AutoSafeParcelable { public static Creator CREATOR = new AutoCreator<>(AccountChangeEvent.class); +======= +import java.util.List; + +public class GetAllCapabilitiesResponse extends AutoSafeParcelable { + @Field(1) + private int versionCode = 1; + @Field(2) + public int statusCode; + @Field(3) + public List capabilities; + + public static final Creator CREATOR = findCreator(GetAllCapabilitiesResponse.class); +>>>>>>> 1cc72500 (Wearable: Invoke callback on WearableService.getAllCapabilities()):play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/GetAllCapabilitiesResponse.java } diff --git a/play-services-wearable/core/src/main/java/org/microg/gms/wearable/WearableServiceImpl.java b/play-services-wearable/core/src/main/java/org/microg/gms/wearable/WearableServiceImpl.java new file mode 100644 index 00000000..1fb2c589 --- /dev/null +++ b/play-services-wearable/core/src/main/java/org/microg/gms/wearable/WearableServiceImpl.java @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2013-2019 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.net.Uri; +import android.os.Handler; +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.util.Base64; +import android.util.Log; + +import com.google.android.gms.common.api.Status; +import com.google.android.gms.wearable.Asset; +import com.google.android.gms.wearable.ConnectionConfiguration; +import com.google.android.gms.wearable.internal.*; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class WearableServiceImpl extends IWearableService.Stub { + private static final String TAG = "GmsWearSvcImpl"; + + private final Context context; + private final String packageName; + private final WearableImpl wearable; + private final Handler mainHandler; + private final CapabilityManager capabilities; + + public WearableServiceImpl(Context context, WearableImpl wearable, String packageName) { + this.context = context; + this.wearable = wearable; + this.packageName = packageName; + this.capabilities = new CapabilityManager(context, wearable, packageName); + this.mainHandler = new Handler(context.getMainLooper()); + } + + private void postMain(IWearableCallbacks callbacks, RemoteExceptionRunnable runnable) { + mainHandler.post(new CallbackRunnable(callbacks) { + @Override + public void run(IWearableCallbacks callbacks) throws RemoteException { + runnable.run(); + } + }); + } + + private void postNetwork(IWearableCallbacks callbacks, RemoteExceptionRunnable runnable) { + this.wearable.networkHandler.post(new CallbackRunnable(callbacks) { + @Override + public void run(IWearableCallbacks callbacks) throws RemoteException { + runnable.run(); + } + }); + } + + /* + * Config + */ + + @Override + public void putConfig(IWearableCallbacks callbacks, final ConnectionConfiguration config) throws RemoteException { + postMain(callbacks, () -> { + wearable.createConnection(config); + callbacks.onStatus(Status.SUCCESS); + }); + } + + @Override + public void deleteConfig(IWearableCallbacks callbacks, final String name) throws RemoteException { + postMain(callbacks, () -> { + wearable.deleteConnection(name); + callbacks.onStatus(Status.SUCCESS); + }); + } + + @Override + public void getConfigs(IWearableCallbacks callbacks) throws RemoteException { + Log.d(TAG, "getConfigs"); + postMain(callbacks, () -> { + try { + callbacks.onGetConfigsResponse(new GetConfigsResponse(0, wearable.getConfigurations())); + } catch (Exception e) { + callbacks.onGetConfigsResponse(new GetConfigsResponse(8, new ConnectionConfiguration[0])); + } + }); + } + + + @Override + public void enableConfig(IWearableCallbacks callbacks, final String name) throws RemoteException { + Log.d(TAG, "enableConfig: " + name); + postMain(callbacks, () -> { + wearable.enableConnection(name); + callbacks.onStatus(Status.SUCCESS); + }); + } + + @Override + public void disableConfig(IWearableCallbacks callbacks, final String name) throws RemoteException { + Log.d(TAG, "disableConfig: " + name); + postMain(callbacks, () -> { + wearable.disableConnection(name); + callbacks.onStatus(Status.SUCCESS); + }); + } + + /* + * DataItems + */ + + @Override + public void putData(IWearableCallbacks callbacks, final PutDataRequest request) throws RemoteException { + Log.d(TAG, "putData: " + request.toString(true)); + this.wearable.networkHandler.post(new CallbackRunnable(callbacks) { + @Override + public void run(IWearableCallbacks callbacks) throws RemoteException { + DataItemRecord record = wearable.putData(request, packageName); + callbacks.onPutDataResponse(new PutDataResponse(0, record.toParcelable())); + } + }); + } + + @Override + public void getDataItem(IWearableCallbacks callbacks, final Uri uri) throws RemoteException { + Log.d(TAG, "getDataItem: " + uri); + postMain(callbacks, () -> { + DataItemRecord record = wearable.getDataItemByUri(uri, packageName); + if (record != null) { + callbacks.onGetDataItemResponse(new GetDataItemResponse(0, record.toParcelable())); + } else { + callbacks.onGetDataItemResponse(new GetDataItemResponse(0, null)); + } + }); + } + + @Override + public void getDataItems(final IWearableCallbacks callbacks) throws RemoteException { + Log.d(TAG, "getDataItems: " + callbacks); + postMain(callbacks, () -> { + callbacks.onDataItemChanged(wearable.getDataItemsAsHolder(packageName)); + }); + } + + @Override + public void getDataItemsByUri(IWearableCallbacks callbacks, Uri uri) throws RemoteException { + getDataItemsByUriWithFilter(callbacks, uri, 0); + } + + @Override + public void getDataItemsByUriWithFilter(IWearableCallbacks callbacks, final Uri uri, int typeFilter) throws RemoteException { + Log.d(TAG, "getDataItemsByUri: " + uri); + postMain(callbacks, () -> { + callbacks.onDataItemChanged(wearable.getDataItemsByUriAsHolder(uri, packageName)); + }); + } + + @Override + public void deleteDataItems(IWearableCallbacks callbacks, Uri uri) throws RemoteException { + deleteDataItemsWithFilter(callbacks, uri, 0); + } + + @Override + public void deleteDataItemsWithFilter(IWearableCallbacks callbacks, final Uri uri, int typeFilter) throws RemoteException { + Log.d(TAG, "deleteDataItems: " + uri); + this.wearable.networkHandler.post(new CallbackRunnable(callbacks) { + @Override + public void run(IWearableCallbacks callbacks) throws RemoteException { + callbacks.onDeleteDataItemsResponse(new DeleteDataItemsResponse(0, wearable.deleteDataItems(uri, packageName))); + } + }); + } + + @Override + public void sendMessage(IWearableCallbacks callbacks, final String targetNodeId, final String path, final byte[] data) throws RemoteException { + Log.d(TAG, "sendMessage: " + targetNodeId + " / " + path + ": " + (data == null ? null : Base64.encodeToString(data, Base64.NO_WRAP))); + this.wearable.networkHandler.post(new CallbackRunnable(callbacks) { + @Override + public void run(IWearableCallbacks callbacks) throws RemoteException { + SendMessageResponse sendMessageResponse = new SendMessageResponse(); + try { + sendMessageResponse.requestId = wearable.sendMessage(packageName, targetNodeId, path, data); + if (sendMessageResponse.requestId == -1) { + sendMessageResponse.statusCode = 4000; + } + } catch (Exception e) { + sendMessageResponse.statusCode = 8; + } + mainHandler.post(() -> { + try { + callbacks.onSendMessageResponse(sendMessageResponse); + } catch (RemoteException e) { + e.printStackTrace(); + } + }); + } + }); + } + + @Override + public void getFdForAsset(IWearableCallbacks callbacks, final Asset asset) throws RemoteException { + Log.d(TAG, "getFdForAsset " + asset); + postMain(callbacks, () -> { + // TODO: Access control + try { + callbacks.onGetFdForAssetResponse(new GetFdForAssetResponse(0, ParcelFileDescriptor.open(wearable.createAssetFile(asset.getDigest()), ParcelFileDescriptor.MODE_READ_ONLY))); + } catch (FileNotFoundException e) { + callbacks.onGetFdForAssetResponse(new GetFdForAssetResponse(8, null)); + } + }); + } + + @Override + public void optInCloudSync(IWearableCallbacks callbacks, boolean enable) throws RemoteException { + callbacks.onStatus(Status.SUCCESS); + } + + @Override + @Deprecated + public void getCloudSyncOptInDone(IWearableCallbacks callbacks) throws RemoteException { + Log.d(TAG, "unimplemented Method: getCloudSyncOptInDone"); + } + + @Override + public void setCloudSyncSetting(IWearableCallbacks callbacks, boolean enable) throws RemoteException { + Log.d(TAG, "unimplemented Method: setCloudSyncSetting"); + } + + @Override + public void getCloudSyncSetting(IWearableCallbacks callbacks) throws RemoteException { + callbacks.onGetCloudSyncSettingResponse(new GetCloudSyncSettingResponse(0, false)); + } + + @Override + public void getCloudSyncOptInStatus(IWearableCallbacks callbacks) throws RemoteException { + Log.d(TAG, "unimplemented Method: getCloudSyncOptInStatus"); + } + + @Override + public void sendRemoteCommand(IWearableCallbacks callbacks, byte b) throws RemoteException { + Log.d(TAG, "unimplemented Method: sendRemoteCommand: " + b); + } + + @Override + public void getLocalNode(IWearableCallbacks callbacks) throws RemoteException { + postMain(callbacks, () -> { + try { + callbacks.onGetLocalNodeResponse(new GetLocalNodeResponse(0, new NodeParcelable(wearable.getLocalNodeId(), wearable.getLocalNodeId()))); + } catch (Exception e) { + callbacks.onGetLocalNodeResponse(new GetLocalNodeResponse(8, null)); + } + }); + } + + @Override + public void getConnectedNodes(IWearableCallbacks callbacks) throws RemoteException { + postMain(callbacks, () -> { + callbacks.onGetConnectedNodesResponse(new GetConnectedNodesResponse(0, wearable.getConnectedNodesParcelableList())); + }); + } + + /* + * Capability + */ + + @Override + public void getConnectedCapability(IWearableCallbacks callbacks, String capability, int nodeFilter) throws RemoteException { + Log.d(TAG, "unimplemented Method: getConnectedCapability " + capability + ", " + nodeFilter); + postMain(callbacks, () -> { + List nodes = new ArrayList<>(); + for (String host : capabilities.getNodesForCapability(capability)) { + nodes.add(new NodeParcelable(host, host)); + } + CapabilityInfoParcelable capabilityInfo = new CapabilityInfoParcelable(capability, nodes); + callbacks.onGetCapabilityResponse(new GetCapabilityResponse(0, capabilityInfo)); + }); + } + + @Override + public void getAllCapabilities(IWearableCallbacks callbacks, int nodeFilter) throws RemoteException { + Log.d(TAG, "unimplemented Method: getConnectedCapaibilties: " + nodeFilter); + callbacks.onGetAllCapabilitiesResponse(new GetAllCapabilitiesResponse()); + } + + @Override + public void addLocalCapability(IWearableCallbacks callbacks, String capability) throws RemoteException { + Log.d(TAG, "unimplemented Method: addLocalCapability: " + capability); + this.wearable.networkHandler.post(new CallbackRunnable(callbacks) { + @Override + public void run(IWearableCallbacks callbacks) throws RemoteException { + callbacks.onAddLocalCapabilityResponse(new AddLocalCapabilityResponse(capabilities.add(capability))); + } + }); + } + + @Override + public void removeLocalCapability(IWearableCallbacks callbacks, String capability) throws RemoteException { + Log.d(TAG, "unimplemented Method: removeLocalCapability: " + capability); + this.wearable.networkHandler.post(new CallbackRunnable(callbacks) { + @Override + public void run(IWearableCallbacks callbacks) throws RemoteException { + callbacks.onRemoveLocalCapabilityResponse(new RemoveLocalCapabilityResponse(capabilities.remove(capability))); + } + }); + } + + @Override + public void addListener(IWearableCallbacks callbacks, AddListenerRequest request) throws RemoteException { + if (request.listener != null) { + wearable.addListener(packageName, request.listener, request.intentFilters); + } + callbacks.onStatus(Status.SUCCESS); + } + + @Override + public void removeListener(IWearableCallbacks callbacks, RemoveListenerRequest request) throws RemoteException { + wearable.removeListener(request.listener); + callbacks.onStatus(Status.SUCCESS); + } + + @Override + public void getStorageInformation(IWearableCallbacks callbacks) throws RemoteException { + Log.d(TAG, "unimplemented Method: getStorageInformation"); + } + + @Override + public void clearStorage(IWearableCallbacks callbacks) throws RemoteException { + Log.d(TAG, "unimplemented Method: clearStorage"); + } + + @Override + public void endCall(IWearableCallbacks callbacks) throws RemoteException { + Log.d(TAG, "unimplemented Method: endCall"); + } + + @Override + public void acceptRingingCall(IWearableCallbacks callbacks) throws RemoteException { + Log.d(TAG, "unimplemented Method: acceptRingingCall"); + } + + @Override + public void silenceRinger(IWearableCallbacks callbacks) throws RemoteException { + Log.d(TAG, "unimplemented Method: silenceRinger"); + } + + /* + * Apple Notification Center Service + */ + + @Override + public void injectAncsNotificationForTesting(IWearableCallbacks callbacks, AncsNotificationParcelable notification) throws RemoteException { + Log.d(TAG, "unimplemented Method: injectAncsNotificationForTesting: " + notification); + } + + @Override + public void doAncsPositiveAction(IWearableCallbacks callbacks, int i) throws RemoteException { + Log.d(TAG, "unimplemented Method: doAncsPositiveAction: " + i); + } + + @Override + public void doAncsNegativeAction(IWearableCallbacks callbacks, int i) throws RemoteException { + Log.d(TAG, "unimplemented Method: doAncsNegativeAction: " + i); + } + + @Override + public void openChannel(IWearableCallbacks callbacks, String s1, String s2) throws RemoteException { + Log.d(TAG, "unimplemented Method: openChannel; " + s1 + ", " + s2); + } + + /* + * Channels + */ + + @Override + public void closeChannel(IWearableCallbacks callbacks, String s) throws RemoteException { + Log.d(TAG, "unimplemented Method: closeChannel: " + s); + } + + @Override + public void closeChannelWithError(IWearableCallbacks callbacks, String s, int errorCode) throws RemoteException { + Log.d(TAG, "unimplemented Method: closeChannelWithError:" + s + ", " + errorCode); + + } + + @Override + public void getChannelInputStream(IWearableCallbacks callbacks, IChannelStreamCallbacks channelCallbacks, String s) throws RemoteException { + Log.d(TAG, "unimplemented Method: getChannelInputStream: " + s); + } + + @Override + public void getChannelOutputStream(IWearableCallbacks callbacks, IChannelStreamCallbacks channelCallbacks, String s) throws RemoteException { + Log.d(TAG, "unimplemented Method: getChannelOutputStream: " + s); + } + + @Override + public void writeChannelInputToFd(IWearableCallbacks callbacks, String s, ParcelFileDescriptor fd) throws RemoteException { + Log.d(TAG, "unimplemented Method: writeChannelInputToFd: " + s); + } + + @Override + public void readChannelOutputFromFd(IWearableCallbacks callbacks, String s, ParcelFileDescriptor fd, long l1, long l2) throws RemoteException { + Log.d(TAG, "unimplemented Method: readChannelOutputFromFd: " + s + ", " + l1 + ", " + l2); + } + + @Override + public void syncWifiCredentials(IWearableCallbacks callbacks) throws RemoteException { + Log.d(TAG, "unimplemented Method: syncWifiCredentials"); + } + + /* + * Connection deprecated + */ + + @Override + @Deprecated + public void putConnection(IWearableCallbacks callbacks, ConnectionConfiguration config) throws RemoteException { + Log.d(TAG, "unimplemented Method: putConnection"); + } + + @Override + @Deprecated + public void getConnection(IWearableCallbacks callbacks) throws RemoteException { + Log.d(TAG, "getConfig"); + postMain(callbacks, () -> { + ConnectionConfiguration[] configurations = wearable.getConfigurations(); + if (configurations == null || configurations.length == 0) { + callbacks.onGetConfigResponse(new GetConfigResponse(1, new ConnectionConfiguration(null, null, 0, 0, false))); + } else { + callbacks.onGetConfigResponse(new GetConfigResponse(0, configurations[0])); + } + }); + } + + @Override + @Deprecated + public void enableConnection(IWearableCallbacks callbacks) throws RemoteException { + postMain(callbacks, () -> { + ConnectionConfiguration[] configurations = wearable.getConfigurations(); + if (configurations.length > 0) { + enableConfig(callbacks, configurations[0].name); + } + }); + } + + @Override + @Deprecated + public void disableConnection(IWearableCallbacks callbacks) throws RemoteException { + postMain(callbacks, () -> { + ConnectionConfiguration[] configurations = wearable.getConfigurations(); + if (configurations.length > 0) { + disableConfig(callbacks, configurations[0].name); + } + }); + } + + @Override + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { + if (super.onTransact(code, data, reply, flags)) return true; + Log.d(TAG, "onTransact [unknown]: " + code + ", " + data + ", " + flags); + return false; + } + + public abstract class CallbackRunnable implements Runnable { + private IWearableCallbacks callbacks; + + public CallbackRunnable(IWearableCallbacks callbacks) { + this.callbacks = callbacks; + } + + @Override + public void run() { + try { + run(callbacks); + } catch (RemoteException e) { + mainHandler.post(() -> { + try { + callbacks.onStatus(Status.CANCELED); + } catch (RemoteException e2) { + Log.w(TAG, e); + } + }); + } + } + + public abstract void run(IWearableCallbacks callbacks) throws RemoteException; + } + + public interface RemoteExceptionRunnable { + void run() throws RemoteException; + } +} diff --git a/play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/IWearableService.aidl b/play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/IWearableService.aidl new file mode 100644 index 00000000..423dc8b3 --- /dev/null +++ b/play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/IWearableService.aidl @@ -0,0 +1,82 @@ +package com.google.android.gms.wearable.internal; + +import com.google.android.gms.wearable.Asset; +import com.google.android.gms.wearable.ConnectionConfiguration; +import com.google.android.gms.wearable.internal.AddListenerRequest; +import com.google.android.gms.wearable.internal.AncsNotificationParcelable; +import com.google.android.gms.wearable.internal.PutDataRequest; +import com.google.android.gms.wearable.internal.RemoveListenerRequest; +import com.google.android.gms.wearable.internal.IChannelStreamCallbacks; +import com.google.android.gms.wearable.internal.IWearableCallbacks; +import com.google.android.gms.wearable.internal.IWearableService; + +interface IWearableService { + // Configs + void putConfig(IWearableCallbacks callbacks, in ConnectionConfiguration config) = 19; + void deleteConfig(IWearableCallbacks callbacks, String name) = 20; + void getConfigs(IWearableCallbacks callbacks) = 21; + void enableConfig(IWearableCallbacks callbacks, String name) = 22; + void disableConfig(IWearableCallbacks callbacks, String name) = 23; + + // DataItems + void putData(IWearableCallbacks callbacks, in PutDataRequest request) = 5; + void getDataItem(IWearableCallbacks callbacks, in Uri uri) = 6; + void getDataItems(IWearableCallbacks callbacks) = 7; + void getDataItemsByUri(IWearableCallbacks callbacks, in Uri uri) = 8; + void getDataItemsByUriWithFilter(IWearableCallbacks callbacks, in Uri uri, int typeFilter) = 39; + void deleteDataItems(IWearableCallbacks callbacks, in Uri uri) = 10; + void deleteDataItemsWithFilter(IWearableCallbacks callbacks, in Uri uri, int typeFilter) = 40; + + void sendMessage(IWearableCallbacks callbacks, String targetNodeId, String path, in byte[] data) = 11; + void getFdForAsset(IWearableCallbacks callbacks, in Asset asset) = 12; + + void getLocalNode(IWearableCallbacks callbacks) = 13; + void getConnectedNodes(IWearableCallbacks callbacks) = 14; + + // Capabilties + void getConnectedCapability(IWearableCallbacks callbacks, String capability, int nodeFilter) = 41; + void getAllCapabilities(IWearableCallbacks callbacks, int nodeFilter) = 42; + void addLocalCapability(IWearableCallbacks callbacks, String capability) = 45; + void removeLocalCapability(IWearableCallbacks callbacks, String capability) = 46; + + void addListener(IWearableCallbacks callbacks, in AddListenerRequest request) = 15; + void removeListener(IWearableCallbacks callbacks, in RemoveListenerRequest request) = 16; + + void getStorageInformation(IWearableCallbacks callbacks) = 17; + void clearStorage(IWearableCallbacks callbacks) = 18; + + void endCall(IWearableCallbacks callbacks) = 24; + void acceptRingingCall(IWearableCallbacks callbacks) = 25; + void silenceRinger(IWearableCallbacks callbacks) = 29; + + // Apple Notification Center Service + void injectAncsNotificationForTesting(IWearableCallbacks callbacks, in AncsNotificationParcelable notification) = 26; + void doAncsPositiveAction(IWearableCallbacks callbacks, int i) = 27; + void doAncsNegativeAction(IWearableCallbacks callbacks, int i) = 28; + + // Channels + void openChannel(IWearableCallbacks callbacks, String s1, String s2) = 30; + void closeChannel(IWearableCallbacks callbacks, String s) = 31; + void closeChannelWithError(IWearableCallbacks callbacks, String s, int errorCode) = 32; + void getChannelInputStream(IWearableCallbacks callbacks, IChannelStreamCallbacks channelCallbacks, String s) = 33; + void getChannelOutputStream(IWearableCallbacks callbacks, IChannelStreamCallbacks channelCallbacks, String s) = 34; + void writeChannelInputToFd(IWearableCallbacks callbacks, String s, in ParcelFileDescriptor fd) = 37; + void readChannelOutputFromFd(IWearableCallbacks callbacks, String s, in ParcelFileDescriptor fd, long l1, long l2) = 38; + + void syncWifiCredentials(IWearableCallbacks callbacks) = 36; + + // Cloud Sync + void optInCloudSync(IWearableCallbacks callbacks, boolean enable) = 47; + void getCloudSyncOptInDone(IWearableCallbacks callbacks) = 48; // deprecated + void setCloudSyncSetting(IWearableCallbacks callbacks, boolean enable) = 49; + void getCloudSyncSetting(IWearableCallbacks callbacks) = 50; + void getCloudSyncOptInStatus(IWearableCallbacks callbacks) = 51; + + void sendRemoteCommand(IWearableCallbacks callbacks, byte b) = 52; + + // deprecated Connection + void putConnection(IWearableCallbacks callbacks, in ConnectionConfiguration config) = 1; + void getConnection(IWearableCallbacks callbacks) = 2; + void enableConnection(IWearableCallbacks callbacks) = 3; + void disableConnection(IWearableCallbacks callbacks) = 4; +}