1 /*
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  */
16 package com.android.car.cluster.renderer;
17 
18 import android.annotation.Nullable;
19 import android.car.cluster.renderer.NavigationRenderer;
20 import android.graphics.Bitmap;
21 import android.os.Handler;
22 import android.os.Looper;
23 import android.os.Message;
24 
25 /**
26  * A wrapper over {@link NavigationRenderer} that runs all its methods in the context of provided
27  * looper. It is guaranteed that all calls will be invoked in order they were called.
28  */
29 public class ThreadSafeNavigationRenderer extends NavigationRenderer {
30 
31     private final Handler mHandler;
32 
33     private final static int MSG_NAV_START = 1;
34     private final static int MSG_NAV_STOP = 2;
35     private final static int MSG_NAV_NEXT_TURN = 3;
36     private final static int MSG_NAV_NEXT_TURN_DISTANCE = 4;
37 
38     /** Creates thread-safe {@link NavigationRenderer}. Returns null if renderer == null */
39     @Nullable
createFor(Looper looper, NavigationRenderer renderer)40     public static NavigationRenderer createFor(Looper looper, NavigationRenderer renderer) {
41         return renderer == null ? null : new ThreadSafeNavigationRenderer(looper, renderer);
42     }
43 
ThreadSafeNavigationRenderer(Looper looper, NavigationRenderer renderer)44     private ThreadSafeNavigationRenderer(Looper looper, NavigationRenderer renderer) {
45         mHandler = new NavigationRendererHandler(looper, renderer);
46     }
47 
48     @Override
onStartNavigation()49     public void onStartNavigation() {
50         mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_START));
51     }
52 
53     @Override
onStopNavigation()54     public void onStopNavigation() {
55         mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_STOP));
56     }
57 
58     @Override
onNextTurnChanged(int event, String road, int turnAngle, int turnNumber, Bitmap image, int turnSide)59     public void onNextTurnChanged(int event, String road, int turnAngle, int turnNumber,
60             Bitmap image, int turnSide) {
61         mHandler.sendMessage(mHandler.obtainMessage(MSG_NAV_NEXT_TURN,
62                 new NextTurn(event, road, turnAngle, turnNumber, image, turnSide)));
63     }
64 
65     @Override
onNextTurnDistanceChanged(int distanceMeters, int timeSeconds)66     public void onNextTurnDistanceChanged(int distanceMeters, int timeSeconds) {
67         mHandler.sendMessage(mHandler.obtainMessage(
68                     MSG_NAV_NEXT_TURN_DISTANCE, distanceMeters, timeSeconds));
69     }
70 
71     private static class NavigationRendererHandler extends RendererHandler<NavigationRenderer> {
72 
NavigationRendererHandler(Looper looper, NavigationRenderer renderer)73         NavigationRendererHandler(Looper looper, NavigationRenderer renderer) {
74             super(looper, renderer);
75         }
76 
77         @Override
handleMessage(Message msg, NavigationRenderer renderer)78         public void handleMessage(Message msg, NavigationRenderer renderer) {
79 
80             switch (msg.what) {
81                 case MSG_NAV_START:
82                     renderer.onStartNavigation();
83                     break;
84                 case MSG_NAV_STOP:
85                     renderer.onStopNavigation();
86                     break;
87                 case MSG_NAV_NEXT_TURN:
88                     NextTurn nt = (NextTurn) msg.obj;
89                     renderer.onNextTurnChanged(nt.event, nt.road, nt.turnAngle, nt.turnNumber,
90                             nt.bitmap, nt.turnSide);
91                     break;
92                 case MSG_NAV_NEXT_TURN_DISTANCE:
93                     renderer.onNextTurnDistanceChanged(msg.arg1, msg.arg2);
94                     break;
95                 default:
96                     throw new IllegalArgumentException("Msg: " + msg.what);
97             }
98         }
99     }
100 
101     private static class NextTurn {
102         private final int event;
103         private final String road;
104         private final int turnAngle;
105         private final int turnNumber;
106         private final Bitmap bitmap;
107         private final int turnSide;
108 
NextTurn(int event, String road, int turnAngle, int turnNumber, Bitmap bitmap, int turnSide)109         NextTurn(int event, String road, int turnAngle, int turnNumber, Bitmap bitmap,
110                 int turnSide) {
111             this.event = event;
112             this.road = road;
113             this.turnAngle = turnAngle;
114             this.turnNumber = turnNumber;
115             this.bitmap = bitmap;
116             this.turnSide = turnSide;
117         }
118     }
119 }
120