blob: 047ed90f9cf9e1934922e3237a005b2210c3aa28 [file] [log] [blame]
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -08001/*
2 * Copyright (C) 2016 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 */
Pavel Maltsev0477e292016-05-27 12:22:36 -070016package android.car.cluster.renderer;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080017
18import android.annotation.Nullable;
Pavel Maltsev8cf86912016-04-01 18:01:51 -070019import android.car.navigation.CarNavigationInstrumentCluster;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080020import android.graphics.Bitmap;
Pavel Maltsev1fd2ff62017-07-05 19:09:07 -070021import android.os.Bundle;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080022import android.os.Handler;
23import android.os.Looper;
24import android.os.Message;
25
Pavel Maltsev0477e292016-05-27 12:22:36 -070026import java.lang.ref.WeakReference;
Pavel Maltsev8cf86912016-04-01 18:01:51 -070027import java.util.concurrent.CountDownLatch;
28
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080029/**
30 * A wrapper over {@link NavigationRenderer} that runs all its methods in the context of provided
31 * looper. It is guaranteed that all calls will be invoked in order they were called.
32 */
Pavel Maltsev0477e292016-05-27 12:22:36 -070033/* package */ class ThreadSafeNavigationRenderer extends NavigationRenderer {
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080034
35 private final Handler mHandler;
Pavel Maltsev8cf86912016-04-01 18:01:51 -070036 private final NavigationRenderer mRenderer;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080037
38 private final static int MSG_NAV_START = 1;
39 private final static int MSG_NAV_STOP = 2;
40 private final static int MSG_NAV_NEXT_TURN = 3;
41 private final static int MSG_NAV_NEXT_TURN_DISTANCE = 4;
Pavel Maltsev1fd2ff62017-07-05 19:09:07 -070042 private final static int MSG_EVENT = 5;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080043
44 /** Creates thread-safe {@link NavigationRenderer}. Returns null if renderer == null */
45 @Nullable
Pavel Maltsev0477e292016-05-27 12:22:36 -070046 static NavigationRenderer createFor(Looper looper, NavigationRenderer renderer) {
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080047 return renderer == null ? null : new ThreadSafeNavigationRenderer(looper, renderer);
48 }
49
50 private ThreadSafeNavigationRenderer(Looper looper, NavigationRenderer renderer) {
Pavel Maltsev8cf86912016-04-01 18:01:51 -070051 mRenderer = renderer;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080052 mHandler = new NavigationRendererHandler(looper, renderer);
53 }
54
55 @Override
Pavel Maltsev8cf86912016-04-01 18:01:51 -070056 public CarNavigationInstrumentCluster getNavigationProperties() {
Pavel Maltsev0477e292016-05-27 12:22:36 -070057 if (mHandler.getLooper() == Looper.myLooper()) {
58 return mRenderer.getNavigationProperties();
59 } else {
60 return runAndWaitResult(mHandler,
61 new RunnableWithResult<CarNavigationInstrumentCluster>() {
62 @Override
63 protected CarNavigationInstrumentCluster createResult() {
64 return mRenderer.getNavigationProperties();
65 }
66 });
67 }
Pavel Maltsev8cf86912016-04-01 18:01:51 -070068 }
69
70 @Override
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080071 public void onStartNavigation() {
72 mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_START));
73 }
74
75 @Override
76 public void onStopNavigation() {
77 mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_STOP));
78 }
79
80 @Override
Keun-young Park3388e782016-10-05 16:28:32 -070081 public void onNextTurnChanged(int event, CharSequence eventName, int turnAngle, int turnNumber,
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080082 Bitmap image, int turnSide) {
83 mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_NEXT_TURN,
Keun-young Park3388e782016-10-05 16:28:32 -070084 new NextTurn(event, eventName, turnAngle, turnNumber, image, turnSide)));
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080085 }
86
87 @Override
Pavel Maltseva928f132016-08-01 16:46:10 -070088 public void onNextTurnDistanceChanged(int distanceMeters, int timeSeconds,
89 int displayDistanceMillis, int displayDistanceUnit) {
90 ManeuverDistance distance = new ManeuverDistance(distanceMeters, timeSeconds,
91 displayDistanceMillis, displayDistanceUnit);
92 mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_NEXT_TURN_DISTANCE, distance));
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080093 }
94
Pavel Maltsev1fd2ff62017-07-05 19:09:07 -070095 @Override
96 public void onEvent(int eventType, Bundle bundle) {
97 mHandler.sendMessage(mHandler.obtainMessage(MSG_EVENT, eventType, 0, bundle));
98 }
99
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800100 private static class NavigationRendererHandler extends RendererHandler<NavigationRenderer> {
101
102 NavigationRendererHandler(Looper looper, NavigationRenderer renderer) {
103 super(looper, renderer);
104 }
105
106 @Override
107 public void handleMessage(Message msg, NavigationRenderer renderer) {
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800108 switch (msg.what) {
109 case MSG_NAV_START:
110 renderer.onStartNavigation();
111 break;
112 case MSG_NAV_STOP:
113 renderer.onStopNavigation();
114 break;
115 case MSG_NAV_NEXT_TURN:
116 NextTurn nt = (NextTurn) msg.obj;
Keun-young Park3388e782016-10-05 16:28:32 -0700117 renderer.onNextTurnChanged(nt.event, nt.eventName, nt.turnAngle, nt.turnNumber,
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800118 nt.bitmap, nt.turnSide);
119 break;
120 case MSG_NAV_NEXT_TURN_DISTANCE:
Pavel Maltseva928f132016-08-01 16:46:10 -0700121 ManeuverDistance d = (ManeuverDistance) msg.obj;
122 renderer.onNextTurnDistanceChanged(
123 d.meters, d.seconds, d.displayDistanceMillis, d.displayDistanceUnit);
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800124 break;
Pavel Maltsev1fd2ff62017-07-05 19:09:07 -0700125 case MSG_EVENT:
126 Bundle bundle = (Bundle) msg.obj;
127 renderer.onEvent(msg.arg1, bundle);
128 break;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800129 default:
130 throw new IllegalArgumentException("Msg: " + msg.what);
131 }
132 }
133 }
134
Jason Tholstrup6ad2b512016-07-14 14:27:37 -0700135 private static <E> E runAndWaitResult(Handler handler, final RunnableWithResult<E> runnable) {
Pavel Maltsev0477e292016-05-27 12:22:36 -0700136 final CountDownLatch latch = new CountDownLatch(1);
Jason Tholstrup6ad2b512016-07-14 14:27:37 -0700137
138 Runnable wrappedRunnable = new Runnable() {
139 @Override
140 public void run() {
141 runnable.run();
142 latch.countDown();
143 }
144 };
145
146 handler.post(wrappedRunnable);
147
Pavel Maltsev8cf86912016-04-01 18:01:51 -0700148 try {
Pavel Maltsev0477e292016-05-27 12:22:36 -0700149 latch.await();
Pavel Maltsev8cf86912016-04-01 18:01:51 -0700150 } catch (InterruptedException e) {
151 throw new RuntimeException(e);
152 }
153 return runnable.getResult();
154 }
155
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800156 private static class NextTurn {
157 private final int event;
Keun-young Park3388e782016-10-05 16:28:32 -0700158 private final CharSequence eventName;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800159 private final int turnAngle;
160 private final int turnNumber;
161 private final Bitmap bitmap;
162 private final int turnSide;
163
Keun-young Park3388e782016-10-05 16:28:32 -0700164 NextTurn(int event, CharSequence eventName, int turnAngle, int turnNumber, Bitmap bitmap,
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800165 int turnSide) {
166 this.event = event;
Keun-young Park3388e782016-10-05 16:28:32 -0700167 this.eventName = eventName;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800168 this.turnAngle = turnAngle;
169 this.turnNumber = turnNumber;
170 this.bitmap = bitmap;
171 this.turnSide = turnSide;
172 }
173 }
Pavel Maltsev8cf86912016-04-01 18:01:51 -0700174
Pavel Maltsev0477e292016-05-27 12:22:36 -0700175 private static abstract class RunnableWithResult<T> implements Runnable {
Pavel Maltsev8cf86912016-04-01 18:01:51 -0700176 private volatile T result;
177
178 protected abstract T createResult();
179
180 @Override
181 public void run() {
182 result = createResult();
183 }
184
185 public T getResult() {
186 return result;
187 }
188 }
Pavel Maltsev0477e292016-05-27 12:22:36 -0700189
190 private static abstract class RendererHandler<T> extends Handler {
191
192 private final WeakReference<T> mRendererRef;
193
194 RendererHandler(Looper looper, T renderer) {
195 super(looper);
196 mRendererRef = new WeakReference<>(renderer);
197 }
198
199 @Override
200 public void handleMessage(Message msg) {
201 T renderer = mRendererRef.get();
202 if (renderer != null) {
203 handleMessage(msg, renderer);
204 }
205 }
206
207 public abstract void handleMessage(Message msg, T renderer);
208 }
Pavel Maltseva928f132016-08-01 16:46:10 -0700209
210 private static class ManeuverDistance {
211 final int meters;
212 final int seconds;
213 final int displayDistanceMillis;
214 final int displayDistanceUnit;
215
216 ManeuverDistance(int meters, int seconds, int displayDistanceMillis,
217 int displayDistanceUnit) {
218 this.meters = meters;
219 this.seconds = seconds;
220 this.displayDistanceMillis = displayDistanceMillis;
221 this.displayDistanceUnit = displayDistanceUnit;
222 }
223 }
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800224}