blob: e9327d8f658a424f4c25cc3ca109f5b4dc6dc4f5 [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 Maltsev8cf86912016-04-01 18:01:51 -070016package android.car.cluster.demorenderer;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080017
18import android.annotation.Nullable;
19import android.car.cluster.renderer.NavigationRenderer;
Pavel Maltsev8cf86912016-04-01 18:01:51 -070020import android.car.navigation.CarNavigationInstrumentCluster;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080021import android.graphics.Bitmap;
22import android.os.Handler;
23import android.os.Looper;
24import android.os.Message;
25
Pavel Maltsev8cf86912016-04-01 18:01:51 -070026import java.util.concurrent.CountDownLatch;
27
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080028/**
29 * A wrapper over {@link NavigationRenderer} that runs all its methods in the context of provided
30 * looper. It is guaranteed that all calls will be invoked in order they were called.
31 */
32public class ThreadSafeNavigationRenderer extends NavigationRenderer {
33
34 private final Handler mHandler;
Pavel Maltsev8cf86912016-04-01 18:01:51 -070035 private final NavigationRenderer mRenderer;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080036
37 private final static int MSG_NAV_START = 1;
38 private final static int MSG_NAV_STOP = 2;
39 private final static int MSG_NAV_NEXT_TURN = 3;
40 private final static int MSG_NAV_NEXT_TURN_DISTANCE = 4;
41
42 /** Creates thread-safe {@link NavigationRenderer}. Returns null if renderer == null */
43 @Nullable
44 public static NavigationRenderer createFor(Looper looper, NavigationRenderer renderer) {
45 return renderer == null ? null : new ThreadSafeNavigationRenderer(looper, renderer);
46 }
47
48 private ThreadSafeNavigationRenderer(Looper looper, NavigationRenderer renderer) {
Pavel Maltsev8cf86912016-04-01 18:01:51 -070049 mRenderer = renderer;
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080050 mHandler = new NavigationRendererHandler(looper, renderer);
51 }
52
53 @Override
Pavel Maltsev8cf86912016-04-01 18:01:51 -070054 public CarNavigationInstrumentCluster getNavigationProperties() {
55 return runAndWaitResult(mHandler, new RunnableWithResult<CarNavigationInstrumentCluster>() {
56 @Override
57 protected CarNavigationInstrumentCluster createResult() {
58 return mRenderer.getNavigationProperties();
59 }
60 });
61 }
62
63 @Override
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -080064 public void onStartNavigation() {
65 mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_START));
66 }
67
68 @Override
69 public void onStopNavigation() {
70 mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_STOP));
71 }
72
73 @Override
74 public void onNextTurnChanged(int event, String road, int turnAngle, int turnNumber,
75 Bitmap image, int turnSide) {
76 mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_NEXT_TURN,
77 new NextTurn(event, road, turnAngle, turnNumber, image, turnSide)));
78 }
79
80 @Override
81 public void onNextTurnDistanceChanged(int distanceMeters, int timeSeconds) {
82 mHandler.sendMessage(mHandler.obtainMessage(
83 MSG_NAV_NEXT_TURN_DISTANCE, distanceMeters, timeSeconds));
84 }
85
86 private static class NavigationRendererHandler extends RendererHandler<NavigationRenderer> {
87
88 NavigationRendererHandler(Looper looper, NavigationRenderer renderer) {
89 super(looper, renderer);
90 }
91
92 @Override
93 public void handleMessage(Message msg, NavigationRenderer renderer) {
94
95 switch (msg.what) {
96 case MSG_NAV_START:
97 renderer.onStartNavigation();
98 break;
99 case MSG_NAV_STOP:
100 renderer.onStopNavigation();
101 break;
102 case MSG_NAV_NEXT_TURN:
103 NextTurn nt = (NextTurn) msg.obj;
104 renderer.onNextTurnChanged(nt.event, nt.road, nt.turnAngle, nt.turnNumber,
105 nt.bitmap, nt.turnSide);
106 break;
107 case MSG_NAV_NEXT_TURN_DISTANCE:
108 renderer.onNextTurnDistanceChanged(msg.arg1, msg.arg2);
109 break;
110 default:
111 throw new IllegalArgumentException("Msg: " + msg.what);
112 }
113 }
114 }
115
Pavel Maltsev8cf86912016-04-01 18:01:51 -0700116 private static <E> E runAndWaitResult(Handler handler, RunnableWithResult<E> runnable) {
117 CountDownLatch latch = new CountDownLatch(1);
118 handler.post(() -> {
119 runnable.run();
120 latch.countDown();
121 });
122 try {
123 latch.wait();
124 } catch (InterruptedException e) {
125 throw new RuntimeException(e);
126 }
127 return runnable.getResult();
128 }
129
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800130 private static class NextTurn {
131 private final int event;
132 private final String road;
133 private final int turnAngle;
134 private final int turnNumber;
135 private final Bitmap bitmap;
136 private final int turnSide;
137
138 NextTurn(int event, String road, int turnAngle, int turnNumber, Bitmap bitmap,
139 int turnSide) {
140 this.event = event;
141 this.road = road;
142 this.turnAngle = turnAngle;
143 this.turnNumber = turnNumber;
144 this.bitmap = bitmap;
145 this.turnSide = turnSide;
146 }
147 }
Pavel Maltsev8cf86912016-04-01 18:01:51 -0700148
149 public abstract class RunnableWithResult<T> implements Runnable {
150 private volatile T result;
151
152 protected abstract T createResult();
153
154 @Override
155 public void run() {
156 result = createResult();
157 }
158
159 public T getResult() {
160 return result;
161 }
162 }
Pavel Maltsev1ecdd6c2016-03-02 16:33:44 -0800163}