blob: d11e0a9b608193438a6bd36f05c88826b689058c [file] [log] [blame]
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -07001/*
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 */
16package android.hardware.location;
17
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -080018import android.annotation.CallbackExecutor;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070019import android.annotation.IntDef;
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -070020import android.annotation.NonNull;
Arthur Ishigurof2b6f012017-11-28 15:21:38 -080021import android.annotation.SystemApi;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070022import android.os.Handler;
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -080023import android.os.HandlerExecutor;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070024
25import java.lang.annotation.Retention;
26import java.lang.annotation.RetentionPolicy;
Daulet Zhanguzinfcc8d862019-12-18 14:42:04 +000027import java.util.Objects;
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -070028import java.util.concurrent.CountDownLatch;
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -080029import java.util.concurrent.Executor;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070030import java.util.concurrent.TimeUnit;
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -070031import java.util.concurrent.TimeoutException;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070032
33/**
34 * A class describing a request sent to the Context Hub Service.
35 *
36 * This object is generated as a result of an asynchronous request sent to the Context Hub
37 * through the ContextHubManager APIs. The caller can either retrieve the result
38 * synchronously through a blocking call ({@link #waitForResponse(long, TimeUnit)}) or
Arthur Ishiguroddb737f2017-12-21 10:32:01 -080039 * asynchronously through a user-defined listener
Arthur Ishigurob3dce5b2018-01-02 09:51:01 -080040 * ({@link #setOnCompleteListener(OnCompleteListener, Executor)} )}).
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070041 *
42 * @param <T> the type of the contents in the transaction response
43 *
44 * @hide
45 */
Arthur Ishigurof2b6f012017-11-28 15:21:38 -080046@SystemApi
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070047public class ContextHubTransaction<T> {
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -070048 private static final String TAG = "ContextHubTransaction";
49
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070050 /**
51 * Constants describing the type of a transaction through the Context Hub Service.
Arthur Ishigurof2b6f012017-11-28 15:21:38 -080052 * {@hide}
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070053 */
54 @Retention(RetentionPolicy.SOURCE)
Jeff Sharkeyce8db992017-12-13 20:05:05 -070055 @IntDef(prefix = { "TYPE_" }, value = {
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070056 TYPE_LOAD_NANOAPP,
57 TYPE_UNLOAD_NANOAPP,
58 TYPE_ENABLE_NANOAPP,
59 TYPE_DISABLE_NANOAPP,
Jeff Sharkeyce8db992017-12-13 20:05:05 -070060 TYPE_QUERY_NANOAPPS
61 })
62 public @interface Type { }
63
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070064 public static final int TYPE_LOAD_NANOAPP = 0;
65 public static final int TYPE_UNLOAD_NANOAPP = 1;
66 public static final int TYPE_ENABLE_NANOAPP = 2;
67 public static final int TYPE_DISABLE_NANOAPP = 3;
68 public static final int TYPE_QUERY_NANOAPPS = 4;
69
70 /**
71 * Constants describing the result of a transaction or request through the Context Hub Service.
Arthur Ishigurof2b6f012017-11-28 15:21:38 -080072 * {@hide}
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070073 */
74 @Retention(RetentionPolicy.SOURCE)
Arthur Ishiguro6100aa72017-12-20 09:35:00 -080075 @IntDef(prefix = { "RESULT_" }, value = {
76 RESULT_SUCCESS,
77 RESULT_FAILED_UNKNOWN,
78 RESULT_FAILED_BAD_PARAMS,
79 RESULT_FAILED_UNINITIALIZED,
Arthur Ishigurof3691da2018-01-02 09:52:21 -080080 RESULT_FAILED_BUSY,
Arthur Ishiguro6100aa72017-12-20 09:35:00 -080081 RESULT_FAILED_AT_HUB,
82 RESULT_FAILED_TIMEOUT,
83 RESULT_FAILED_SERVICE_INTERNAL_FAILURE,
84 RESULT_FAILED_HAL_UNAVAILABLE
Jeff Sharkeyce8db992017-12-13 20:05:05 -070085 })
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070086 public @interface Result {}
Arthur Ishiguro6100aa72017-12-20 09:35:00 -080087 public static final int RESULT_SUCCESS = 0;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070088 /**
89 * Generic failure mode.
90 */
Arthur Ishiguro6100aa72017-12-20 09:35:00 -080091 public static final int RESULT_FAILED_UNKNOWN = 1;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070092 /**
93 * Failure mode when the request parameters were not valid.
94 */
Arthur Ishiguro6100aa72017-12-20 09:35:00 -080095 public static final int RESULT_FAILED_BAD_PARAMS = 2;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070096 /**
97 * Failure mode when the Context Hub is not initialized.
98 */
Arthur Ishiguro6100aa72017-12-20 09:35:00 -080099 public static final int RESULT_FAILED_UNINITIALIZED = 3;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700100 /**
101 * Failure mode when there are too many transactions pending.
102 */
Arthur Ishigurof3691da2018-01-02 09:52:21 -0800103 public static final int RESULT_FAILED_BUSY = 4;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700104 /**
105 * Failure mode when the request went through, but failed asynchronously at the hub.
106 */
Arthur Ishiguro6100aa72017-12-20 09:35:00 -0800107 public static final int RESULT_FAILED_AT_HUB = 5;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700108 /**
109 * Failure mode when the transaction has timed out.
110 */
Arthur Ishiguro6100aa72017-12-20 09:35:00 -0800111 public static final int RESULT_FAILED_TIMEOUT = 6;
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700112 /**
113 * Failure mode when the transaction has failed internally at the service.
114 */
Arthur Ishiguro6100aa72017-12-20 09:35:00 -0800115 public static final int RESULT_FAILED_SERVICE_INTERNAL_FAILURE = 7;
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800116 /**
117 * Failure mode when the Context Hub HAL was not available.
118 */
Arthur Ishiguro6100aa72017-12-20 09:35:00 -0800119 public static final int RESULT_FAILED_HAL_UNAVAILABLE = 8;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700120
121 /**
122 * A class describing the response for a ContextHubTransaction.
123 *
124 * @param <R> the type of the contents in the response
125 */
126 public static class Response<R> {
127 /*
128 * The result of the transaction.
129 */
130 @ContextHubTransaction.Result
131 private int mResult;
132
133 /*
134 * The contents of the response from the Context Hub.
135 */
136 private R mContents;
137
138 Response(@ContextHubTransaction.Result int result, R contents) {
139 mResult = result;
140 mContents = contents;
141 }
142
143 @ContextHubTransaction.Result
144 public int getResult() {
145 return mResult;
146 }
147
148 public R getContents() {
149 return mContents;
150 }
151 }
152
153 /**
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800154 * An interface describing the listener for a transaction completion.
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700155 *
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800156 * @param <L> the type of the contents in the transaction response
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700157 */
158 @FunctionalInterface
Arthur Ishigurob3dce5b2018-01-02 09:51:01 -0800159 public interface OnCompleteListener<L> {
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700160 /**
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800161 * The listener function to invoke when the transaction completes.
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700162 *
163 * @param transaction the transaction that this callback was attached to.
164 * @param response the response of the transaction.
165 */
166 void onComplete(
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800167 ContextHubTransaction<L> transaction, ContextHubTransaction.Response<L> response);
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700168 }
169
170 /*
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700171 * The type of the transaction.
172 */
173 @Type
174 private int mTransactionType;
175
176 /*
177 * The response of the transaction.
178 */
179 private ContextHubTransaction.Response<T> mResponse;
180
181 /*
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800182 * The executor to invoke the onComplete async callback.
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700183 */
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800184 private Executor mExecutor = null;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700185
186 /*
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800187 * The listener to be invoked when the transaction completes.
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700188 */
Arthur Ishigurob3dce5b2018-01-02 09:51:01 -0800189 private ContextHubTransaction.OnCompleteListener<T> mListener = null;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700190
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700191 /*
192 * Synchronization latch used to block on response.
193 */
194 private final CountDownLatch mDoneSignal = new CountDownLatch(1);
195
196 /*
197 * true if the response has been set throught setResponse, false otherwise.
198 */
199 private boolean mIsResponseSet = false;
200
201 ContextHubTransaction(@Type int type) {
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700202 mTransactionType = type;
203 }
204
205 /**
Arthur Ishiguro4493e142017-11-27 16:26:34 -0800206 * Converts a transaction type to a human-readable string
207 *
208 * @param type the type of a transaction
209 * @param upperCase {@code true} if upper case the first letter, {@code false} otherwise
210 * @return a string describing the transaction
211 */
212 public static String typeToString(@Type int type, boolean upperCase) {
213 switch (type) {
214 case ContextHubTransaction.TYPE_LOAD_NANOAPP:
215 return upperCase ? "Load" : "load";
216 case ContextHubTransaction.TYPE_UNLOAD_NANOAPP:
217 return upperCase ? "Unload" : "unload";
218 case ContextHubTransaction.TYPE_ENABLE_NANOAPP:
219 return upperCase ? "Enable" : "enable";
220 case ContextHubTransaction.TYPE_DISABLE_NANOAPP:
221 return upperCase ? "Disable" : "disable";
222 case ContextHubTransaction.TYPE_QUERY_NANOAPPS:
223 return upperCase ? "Query" : "query";
224 default:
225 return upperCase ? "Unknown" : "unknown";
226 }
227 }
228
229 /**
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700230 * @return the type of the transaction
231 */
232 @Type
233 public int getType() {
234 return mTransactionType;
235 }
236
237 /**
238 * Waits to receive the asynchronous transaction result.
239 *
240 * This function blocks until the Context Hub Service has received a response
241 * for the transaction represented by this object by the Context Hub, or a
242 * specified timeout period has elapsed.
243 *
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700244 * If the specified timeout has passed, a TimeoutException will be thrown and the caller may
245 * retry the invocation of this method at a later time.
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700246 *
247 * @param timeout the timeout duration
248 * @param unit the unit of the timeout
249 *
250 * @return the transaction response
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700251 *
252 * @throws InterruptedException if the current thread is interrupted while waiting for response
253 * @throws TimeoutException if the timeout period has passed
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700254 */
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700255 public ContextHubTransaction.Response<T> waitForResponse(
256 long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
257 boolean success = mDoneSignal.await(timeout, unit);
258
259 if (!success) {
260 throw new TimeoutException("Timed out while waiting for transaction");
261 }
262
263 return mResponse;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700264 }
265
266 /**
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800267 * Sets the listener to be invoked invoked when the transaction completes.
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700268 *
269 * This function provides an asynchronous approach to retrieve the result of the
270 * transaction. When the transaction response has been provided by the Context Hub,
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800271 * the given listener will be invoked.
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700272 *
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800273 * If the transaction has already completed at the time of invocation, the listener
274 * will be immediately invoked. If the transaction has been invalidated,
275 * the listener will never be invoked.
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700276 *
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700277 * A transaction can be invalidated if the process owning the transaction is no longer active
278 * and the reference to this object is lost.
279 *
Arthur Ishigurob3dce5b2018-01-02 09:51:01 -0800280 * This method or {@link #setOnCompleteListener(ContextHubTransaction.OnCompleteListener)} can
281 * only be invoked once, or an IllegalStateException will be thrown.
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700282 *
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800283 * @param listener the listener to be invoked upon completion
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800284 * @param executor the executor to invoke the callback
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700285 *
286 * @throws IllegalStateException if this method is called multiple times
287 * @throws NullPointerException if the callback or handler is null
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700288 */
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800289 public void setOnCompleteListener(
Arthur Ishigurob3dce5b2018-01-02 09:51:01 -0800290 @NonNull ContextHubTransaction.OnCompleteListener<T> listener,
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800291 @NonNull @CallbackExecutor Executor executor) {
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700292 synchronized (this) {
Daulet Zhanguzinfcc8d862019-12-18 14:42:04 +0000293 Objects.requireNonNull(listener, "OnCompleteListener cannot be null");
294 Objects.requireNonNull(executor, "Executor cannot be null");
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800295 if (mListener != null) {
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700296 throw new IllegalStateException(
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800297 "Cannot set ContextHubTransaction listener multiple times");
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700298 }
299
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800300 mListener = listener;
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800301 mExecutor = executor;
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700302
303 if (mDoneSignal.getCount() == 0) {
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800304 mExecutor.execute(() -> mListener.onComplete(this, mResponse));
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700305 }
306 }
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700307 }
308
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700309 /**
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800310 * Sets the listener to be invoked invoked when the transaction completes.
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700311 *
Arthur Ishigurob3dce5b2018-01-02 09:51:01 -0800312 * Equivalent to {@link #setOnCompleteListener(ContextHubTransaction.OnCompleteListener,
313 * Executor)} with the executor using the main thread's Looper.
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700314 *
Arthur Ishigurob3dce5b2018-01-02 09:51:01 -0800315 * This method or {@link #setOnCompleteListener(ContextHubTransaction.OnCompleteListener,
316 * Executor)} can only be invoked once, or an IllegalStateException will be thrown.
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700317 *
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800318 * @param listener the listener to be invoked upon completion
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700319 *
320 * @throws IllegalStateException if this method is called multiple times
321 * @throws NullPointerException if the callback is null
322 */
Arthur Ishigurob3dce5b2018-01-02 09:51:01 -0800323 public void setOnCompleteListener(
324 @NonNull ContextHubTransaction.OnCompleteListener<T> listener) {
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800325 setOnCompleteListener(listener, new HandlerExecutor(Handler.getMain()));
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700326 }
327
328 /**
329 * Sets the response of the transaction.
330 *
331 * This method should only be invoked by ContextHubManager as a result of a callback from
332 * the Context Hub Service indicating the response from a transaction. This method should not be
333 * invoked more than once.
334 *
335 * @param response the response to set
336 *
337 * @throws IllegalStateException if this method is invoked multiple times
338 * @throws NullPointerException if the response is null
339 */
Arthur Ishiguroe35a6de2017-12-20 15:30:51 -0800340 /* package */ void setResponse(ContextHubTransaction.Response<T> response) {
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700341 synchronized (this) {
Daulet Zhanguzinfcc8d862019-12-18 14:42:04 +0000342 Objects.requireNonNull(response, "Response cannot be null");
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700343 if (mIsResponseSet) {
344 throw new IllegalStateException(
345 "Cannot set response of ContextHubTransaction multiple times");
346 }
347
348 mResponse = response;
349 mIsResponseSet = true;
350
351 mDoneSignal.countDown();
Arthur Ishiguroddb737f2017-12-21 10:32:01 -0800352 if (mListener != null) {
353 mExecutor.execute(() -> mListener.onComplete(this, mResponse));
Arthur Ishiguro6c37fd02017-10-26 15:36:22 -0700354 }
355 }
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700356 }
357}