1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.wearable;
18 
19 import android.Manifest;
20 import android.annotation.CallbackExecutor;
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SystemApi;
26 import android.annotation.SystemService;
27 import android.app.ambientcontext.AmbientContextEvent;
28 import android.content.Context;
29 import android.os.Binder;
30 import android.os.ParcelFileDescriptor;
31 import android.os.PersistableBundle;
32 import android.os.RemoteCallback;
33 import android.os.RemoteException;
34 import android.os.SharedMemory;
35 import android.service.wearable.WearableSensingService;
36 import android.system.OsConstants;
37 
38 import java.util.concurrent.Executor;
39 import java.util.function.Consumer;
40 
41 /**
42  * Allows granted apps to manage the WearableSensingService.
43  * Applications are responsible for managing the connection to Wearables. Applications can choose
44  * to provide a data stream to the WearableSensingService to use for
45  * computing {@link AmbientContextEvent}s. Applications can also optionally provide their own
46  * defined data to power the detection of {@link AmbientContextEvent}s.
47  * Methods on this class requires the caller to hold and be granted the
48  * {@link Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE}.
49  *
50  * <p>The use of "Wearable" here is not the same as the Android Wear platform and should be treated
51  * separately. </p>
52  *
53  * @hide
54  */
55 
56 @SystemApi
57 @SystemService(Context.WEARABLE_SENSING_SERVICE)
58 public class WearableSensingManager {
59     /**
60      * The bundle key for the service status query result, used in
61      * {@code RemoteCallback#sendResult}.
62      *
63      * @hide
64      */
65     public static final String STATUS_RESPONSE_BUNDLE_KEY =
66             "android.app.wearable.WearableSensingStatusBundleKey";
67 
68 
69     /**
70      * An unknown status.
71      */
72     public static final int STATUS_UNKNOWN = 0;
73 
74     /**
75      * The value of the status code that indicates success.
76      */
77     public static final int STATUS_SUCCESS = 1;
78 
79     /**
80      * The value of the status code that indicates one or more of the
81      * requested events are not supported.
82      */
83     public static final int STATUS_UNSUPPORTED = 2;
84 
85     /**
86      * The value of the status code that indicates service not available.
87      */
88     public static final int STATUS_SERVICE_UNAVAILABLE = 3;
89 
90     /**
91      * The value of the status code that there's no connection to the wearable.
92      */
93     public static final int STATUS_WEARABLE_UNAVAILABLE = 4;
94 
95     /**
96      * The value of the status code that the app is not granted access.
97      */
98     public static final int STATUS_ACCESS_DENIED = 5;
99 
100     /** @hide */
101     @IntDef(prefix = { "STATUS_" }, value = {
102             STATUS_UNKNOWN,
103             STATUS_SUCCESS,
104             STATUS_UNSUPPORTED,
105             STATUS_SERVICE_UNAVAILABLE,
106             STATUS_WEARABLE_UNAVAILABLE,
107             STATUS_ACCESS_DENIED
108     }) public @interface StatusCode {}
109 
110     private final Context mContext;
111     private final IWearableSensingManager mService;
112 
113     /**
114      * {@hide}
115      */
WearableSensingManager(Context context, IWearableSensingManager service)116     public WearableSensingManager(Context context, IWearableSensingManager service) {
117         mContext = context;
118         mService = service;
119     }
120 
121     /**
122      * Provides a data stream to the WearableSensingService that's backed by the
123      * parcelFileDescriptor, and sends the result to the {@link Consumer} right after the call.
124      * This is used by applications that will also provide an implementation of
125      * an isolated WearableSensingService. If the data stream was provided successfully
126      * {@link WearableSensingManager#STATUS_SUCCESS} will be provided.
127      *
128      * @param parcelFileDescriptor The data stream to provide
129      * @param executor Executor on which to run the consumer callback
130      * @param statusConsumer A consumer that handles the status codes, which is returned
131      *                 right after the call.
132      */
133     @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
provideDataStream( @onNull ParcelFileDescriptor parcelFileDescriptor, @NonNull @CallbackExecutor Executor executor, @NonNull @StatusCode Consumer<Integer> statusConsumer)134     public void provideDataStream(
135             @NonNull ParcelFileDescriptor parcelFileDescriptor,
136             @NonNull @CallbackExecutor Executor executor,
137             @NonNull @StatusCode Consumer<Integer> statusConsumer) {
138         try {
139             RemoteCallback callback = new RemoteCallback(result -> {
140                 int status = result.getInt(STATUS_RESPONSE_BUNDLE_KEY);
141                 final long identity = Binder.clearCallingIdentity();
142                 try {
143                     executor.execute(() -> statusConsumer.accept(status));
144                 } finally {
145                     Binder.restoreCallingIdentity(identity);
146                 }
147             });
148             mService.provideDataStream(parcelFileDescriptor, callback);
149         } catch (RemoteException e) {
150             throw e.rethrowFromSystemServer();
151         }
152     }
153 
154     /**
155      * Sets configuration and provides read-only data in a {@link PersistableBundle} that may be
156      * used by the WearableSensingService, and sends the result to the {@link Consumer}
157      * right after the call. It is dependent on the application to
158      * define the type of data to provide. This is used by applications that will also
159      * provide an implementation of an isolated WearableSensingService. If the data was
160      * provided successfully {@link WearableSensingManager#STATUS_SUCCESS} will be povided.
161      *
162      * @param data Application configuration data to provide to the {@link WearableSensingService}.
163      *             PersistableBundle does not allow any remotable objects or other contents
164      *             that can be used to communicate with other processes.
165      * @param sharedMemory The unrestricted data blob to
166      *                     provide to the {@link WearableSensingService}. Use this to provide the
167      *                     sensing models data or other such data to the trusted process.
168      *                     The sharedMemory must be read only and protected with
169      *                     {@link OsConstants.PROT_READ}.
170      *                     Other operations will be removed by the system.
171      * @param executor Executor on which to run the consumer callback
172      * @param statusConsumer A consumer that handles the status codes, which is returned
173      *                     right after the call
174      */
175     @RequiresPermission(Manifest.permission.MANAGE_WEARABLE_SENSING_SERVICE)
provideData( @onNull PersistableBundle data, @Nullable SharedMemory sharedMemory, @NonNull @CallbackExecutor Executor executor, @NonNull @StatusCode Consumer<Integer> statusConsumer)176     public void provideData(
177             @NonNull PersistableBundle data, @Nullable SharedMemory sharedMemory,
178             @NonNull @CallbackExecutor Executor executor,
179             @NonNull @StatusCode Consumer<Integer> statusConsumer) {
180         try {
181             RemoteCallback callback = new RemoteCallback(result -> {
182                 int status = result.getInt(STATUS_RESPONSE_BUNDLE_KEY);
183                 final long identity = Binder.clearCallingIdentity();
184                 try {
185                     executor.execute(() -> statusConsumer.accept(status));
186                 } finally {
187                     Binder.restoreCallingIdentity(identity);
188                 }
189             });
190             mService.provideData(data, sharedMemory, callback);
191         } catch (RemoteException e) {
192             throw e.rethrowFromSystemServer();
193         }
194     }
195 
196 }
197