• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 package android.hardware.location;
17 
18 import android.annotation.CallbackExecutor;
19 import android.annotation.FlaggedApi;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.SystemApi;
23 import android.chre.flags.Flags;
24 import android.os.Handler;
25 import android.os.HandlerExecutor;
26 
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 import java.util.Objects;
30 import java.util.concurrent.CountDownLatch;
31 import java.util.concurrent.Executor;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.TimeoutException;
34 
35 /**
36  * A class describing a request sent to the Context Hub Service.
37  *
38  * This object is generated as a result of an asynchronous request sent to the Context Hub
39  * through the ContextHubManager APIs. The caller can either retrieve the result
40  * synchronously through a blocking call ({@link #waitForResponse(long, TimeUnit)}) or
41  * asynchronously through a user-defined listener
42  * ({@link #setOnCompleteListener(OnCompleteListener, Executor)} )}).
43  *
44  * @param <T> the type of the contents in the transaction response
45  *
46  * @hide
47  */
48 @SystemApi
49 public class ContextHubTransaction<T> {
50     private static final String TAG = "ContextHubTransaction";
51 
52     /**
53      * Constants describing the type of a transaction through the Context Hub Service.
54      *
55      * @hide
56      */
57     @Retention(RetentionPolicy.SOURCE)
58     @IntDef(
59             prefix = {"TYPE_"},
60             value = {
61                 TYPE_LOAD_NANOAPP,
62                 TYPE_UNLOAD_NANOAPP,
63                 TYPE_ENABLE_NANOAPP,
64                 TYPE_DISABLE_NANOAPP,
65                 TYPE_QUERY_NANOAPPS,
66                 TYPE_RELIABLE_MESSAGE,
67                 TYPE_HUB_MESSAGE_DEFAULT,
68                 TYPE_HUB_MESSAGE_REQUIRES_RESPONSE,
69             })
70     public @interface Type {}
71 
72     public static final int TYPE_LOAD_NANOAPP = 0;
73     public static final int TYPE_UNLOAD_NANOAPP = 1;
74     public static final int TYPE_ENABLE_NANOAPP = 2;
75     public static final int TYPE_DISABLE_NANOAPP = 3;
76     public static final int TYPE_QUERY_NANOAPPS = 4;
77     public static final int TYPE_RELIABLE_MESSAGE = 5;
78 
79     @FlaggedApi(Flags.FLAG_OFFLOAD_API)
80     public static final int TYPE_HUB_MESSAGE_DEFAULT = 6;
81 
82     @FlaggedApi(Flags.FLAG_OFFLOAD_API)
83     public static final int TYPE_HUB_MESSAGE_REQUIRES_RESPONSE = 7;
84 
85     /**
86      * Constants describing the result of a transaction or request through the Context Hub Service.
87      *
88      * @hide
89      */
90     @Retention(RetentionPolicy.SOURCE)
91     @IntDef(
92             prefix = {"RESULT_"},
93             value = {
94                 RESULT_SUCCESS,
95                 RESULT_FAILED_UNKNOWN,
96                 RESULT_FAILED_BAD_PARAMS,
97                 RESULT_FAILED_UNINITIALIZED,
98                 RESULT_FAILED_BUSY,
99                 RESULT_FAILED_AT_HUB,
100                 RESULT_FAILED_TIMEOUT,
101                 RESULT_FAILED_SERVICE_INTERNAL_FAILURE,
102                 RESULT_FAILED_HAL_UNAVAILABLE,
103                 RESULT_FAILED_NOT_SUPPORTED,
104             })
105     public @interface Result {}
106 
107     public static final int RESULT_SUCCESS = 0;
108     /**
109      * Generic failure mode.
110      */
111     public static final int RESULT_FAILED_UNKNOWN = 1;
112     /**
113      * Failure mode when the request parameters were not valid.
114      */
115     public static final int RESULT_FAILED_BAD_PARAMS = 2;
116     /**
117      * Failure mode when the Context Hub is not initialized.
118      */
119     public static final int RESULT_FAILED_UNINITIALIZED = 3;
120     /**
121      * Failure mode when there are too many transactions pending.
122      */
123     public static final int RESULT_FAILED_BUSY = 4;
124     /**
125      * Failure mode when the request went through, but failed asynchronously at the hub.
126      */
127     public static final int RESULT_FAILED_AT_HUB = 5;
128     /**
129      * Failure mode when the transaction has timed out.
130      */
131     public static final int RESULT_FAILED_TIMEOUT = 6;
132     /**
133      * Failure mode when the transaction has failed internally at the service.
134      */
135     public static final int RESULT_FAILED_SERVICE_INTERNAL_FAILURE = 7;
136     /**
137      * Failure mode when the Context Hub HAL was not available.
138      */
139     public static final int RESULT_FAILED_HAL_UNAVAILABLE = 8;
140 
141     /** Failure mode when the operation is not supported. */
142     public static final int RESULT_FAILED_NOT_SUPPORTED = 9;
143 
144     /**
145      * A class describing the response for a ContextHubTransaction.
146      *
147      * @param <R> the type of the contents in the response
148      */
149     public static class Response<R> {
150         /*
151          * The result of the transaction.
152          */
153         @ContextHubTransaction.Result
154         private int mResult;
155 
156         /*
157          * The contents of the response from the Context Hub.
158          */
159         private R mContents;
160 
161         /** @hide */
Response(@ontextHubTransaction.Result int result, R contents)162         public Response(@ContextHubTransaction.Result int result, R contents) {
163             mResult = result;
164             mContents = contents;
165         }
166 
167         @ContextHubTransaction.Result
getResult()168         public int getResult() {
169             return mResult;
170         }
171 
getContents()172         public R getContents() {
173             return mContents;
174         }
175     }
176 
177     /**
178      * An interface describing the listener for a transaction completion.
179      *
180      * @param <L> the type of the contents in the transaction response
181      */
182     @FunctionalInterface
183     public interface OnCompleteListener<L> {
184         /**
185          * The listener function to invoke when the transaction completes.
186          *
187          * @param transaction the transaction that this callback was attached to.
188          * @param response the response of the transaction.
189          */
onComplete( ContextHubTransaction<L> transaction, ContextHubTransaction.Response<L> response)190         void onComplete(
191                 ContextHubTransaction<L> transaction, ContextHubTransaction.Response<L> response);
192     }
193 
194     /*
195      * The type of the transaction.
196      */
197     @Type
198     private int mTransactionType;
199 
200     /*
201      * The response of the transaction.
202      */
203     private ContextHubTransaction.Response<T> mResponse;
204 
205     /*
206      * The executor to invoke the onComplete async callback.
207      */
208     private Executor mExecutor = null;
209 
210     /*
211      * The listener to be invoked when the transaction completes.
212      */
213     private ContextHubTransaction.OnCompleteListener<T> mListener = null;
214 
215     /*
216      * Synchronization latch used to block on response.
217      */
218     private final CountDownLatch mDoneSignal = new CountDownLatch(1);
219 
220     /*
221      * true if the response has been set throught setResponse, false otherwise.
222      */
223     private boolean mIsResponseSet = false;
224 
225     /** @hide */
ContextHubTransaction(@ype int type)226     public ContextHubTransaction(@Type int type) {
227         mTransactionType = type;
228     }
229 
230     /**
231      * Converts a transaction type to a human-readable string
232      *
233      * @param type the type of a transaction
234      * @param upperCase {@code true} if upper case the first letter, {@code false} otherwise
235      * @return a string describing the transaction
236      */
typeToString(@ype int type, boolean upperCase)237     public static String typeToString(@Type int type, boolean upperCase) {
238         switch (type) {
239             case ContextHubTransaction.TYPE_LOAD_NANOAPP:
240                 return upperCase ? "Load" : "load";
241             case ContextHubTransaction.TYPE_UNLOAD_NANOAPP:
242                 return upperCase ? "Unload" : "unload";
243             case ContextHubTransaction.TYPE_ENABLE_NANOAPP:
244                 return upperCase ? "Enable" : "enable";
245             case ContextHubTransaction.TYPE_DISABLE_NANOAPP:
246                 return upperCase ? "Disable" : "disable";
247             case ContextHubTransaction.TYPE_QUERY_NANOAPPS:
248                 return upperCase ? "Query" : "query";
249             case ContextHubTransaction.TYPE_RELIABLE_MESSAGE:
250                 return upperCase ? "Reliable Message" : "reliable message";
251             default:
252                 return upperCase ? "Unknown" : "unknown";
253         }
254     }
255 
256     /**
257      * @return the type of the transaction
258      */
259     @Type
getType()260     public int getType() {
261         return mTransactionType;
262     }
263 
264     /**
265      * Waits to receive the asynchronous transaction result.
266      *
267      * This function blocks until the Context Hub Service has received a response
268      * for the transaction represented by this object by the Context Hub, or a
269      * specified timeout period has elapsed.
270      *
271      * If the specified timeout has passed, a TimeoutException will be thrown and the caller may
272      * retry the invocation of this method at a later time.
273      *
274      * @param timeout the timeout duration
275      * @param unit the unit of the timeout
276      *
277      * @return the transaction response
278      *
279      * @throws InterruptedException if the current thread is interrupted while waiting for response
280      * @throws TimeoutException if the timeout period has passed
281      */
waitForResponse( long timeout, TimeUnit unit)282     public ContextHubTransaction.Response<T> waitForResponse(
283             long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
284         boolean success = mDoneSignal.await(timeout, unit);
285 
286         if (!success) {
287             throw new TimeoutException("Timed out while waiting for transaction");
288         }
289 
290         return mResponse;
291     }
292 
293     /**
294      * Sets the listener to be invoked invoked when the transaction completes.
295      *
296      * This function provides an asynchronous approach to retrieve the result of the
297      * transaction. When the transaction response has been provided by the Context Hub,
298      * the given listener will be invoked.
299      *
300      * If the transaction has already completed at the time of invocation, the listener
301      * will be immediately invoked. If the transaction has been invalidated,
302      * the listener will never be invoked.
303      *
304      * A transaction can be invalidated if the process owning the transaction is no longer active
305      * and the reference to this object is lost.
306      *
307      * This method or {@link #setOnCompleteListener(ContextHubTransaction.OnCompleteListener)} can
308      * only be invoked once, or an IllegalStateException will be thrown.
309      *
310      * @param listener the listener to be invoked upon completion
311      * @param executor the executor to invoke the callback
312      *
313      * @throws IllegalStateException if this method is called multiple times
314      * @throws NullPointerException if the callback or handler is null
315      */
setOnCompleteListener( @onNull ContextHubTransaction.OnCompleteListener<T> listener, @NonNull @CallbackExecutor Executor executor)316     public void setOnCompleteListener(
317             @NonNull ContextHubTransaction.OnCompleteListener<T> listener,
318             @NonNull @CallbackExecutor Executor executor) {
319         synchronized (this) {
320             Objects.requireNonNull(listener, "OnCompleteListener cannot be null");
321             Objects.requireNonNull(executor, "Executor cannot be null");
322             if (mListener != null) {
323                 throw new IllegalStateException(
324                         "Cannot set ContextHubTransaction listener multiple times");
325             }
326 
327             mListener = listener;
328             mExecutor = executor;
329 
330             if (mDoneSignal.getCount() == 0) {
331                 mExecutor.execute(() -> mListener.onComplete(this, mResponse));
332             }
333         }
334     }
335 
336     /**
337      * Sets the listener to be invoked invoked when the transaction completes.
338      *
339      * Equivalent to {@link #setOnCompleteListener(ContextHubTransaction.OnCompleteListener,
340      * Executor)} with the executor using the main thread's Looper.
341      *
342      * This method or {@link #setOnCompleteListener(ContextHubTransaction.OnCompleteListener,
343      * Executor)} can only be invoked once, or an IllegalStateException will be thrown.
344      *
345      * @param listener the listener to be invoked upon completion
346      *
347      * @throws IllegalStateException if this method is called multiple times
348      * @throws NullPointerException if the callback is null
349      */
setOnCompleteListener( @onNull ContextHubTransaction.OnCompleteListener<T> listener)350     public void setOnCompleteListener(
351             @NonNull ContextHubTransaction.OnCompleteListener<T> listener) {
352         setOnCompleteListener(listener, new HandlerExecutor(Handler.getMain()));
353     }
354 
355     /**
356      * Sets the response of the transaction.
357      *
358      * <p>This method should only be invoked by ContextHubManager as a result of a callback from the
359      * Context Hub Service indicating the response from a transaction. This method should not be
360      * invoked more than once.
361      *
362      * @param response the response to set
363      * @throws IllegalStateException if this method is invoked multiple times
364      * @throws NullPointerException if the response is null
365      * @hide
366      */
setResponse(ContextHubTransaction.Response<T> response)367     public void setResponse(ContextHubTransaction.Response<T> response) {
368         synchronized (this) {
369             Objects.requireNonNull(response, "Response cannot be null");
370             if (mIsResponseSet) {
371                 throw new IllegalStateException(
372                         "Cannot set response of ContextHubTransaction multiple times");
373             }
374 
375             mResponse = response;
376             mIsResponseSet = true;
377 
378             mDoneSignal.countDown();
379             if (mListener != null) {
380                 mExecutor.execute(() -> mListener.onComplete(this, mResponse));
381             }
382         }
383     }
384 }
385