10477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev/*
20477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * Copyright (C) 2016 The Android Open Source Project
30477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev *
40477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * Licensed under the Apache License, Version 2.0 (the "License");
50477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * you may not use this file except in compliance with the License.
60477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * You may obtain a copy of the License at
70477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev *
80477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev *      http://www.apache.org/licenses/LICENSE-2.0
90477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev *
100477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * Unless required by applicable law or agreed to in writing, software
110477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * distributed under the License is distributed on an "AS IS" BASIS,
120477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * See the License for the specific language governing permissions and
140477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * limitations under the License.
150477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev */
160477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevpackage android.car.cluster.renderer;
170477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
180477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.annotation.CallSuper;
1903cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsevimport android.annotation.MainThread;
200477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.annotation.SystemApi;
210477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.app.Service;
220477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.car.CarLibLog;
230477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.car.navigation.CarNavigationInstrumentCluster;
240477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.content.Intent;
250477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.graphics.Bitmap;
2603cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsevimport android.os.Handler;
270477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.os.IBinder;
280477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.os.Looper;
2903cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsevimport android.os.Message;
300477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.os.RemoteException;
310477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.util.Log;
320477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.util.Pair;
3303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsevimport android.view.KeyEvent;
340477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
350477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport java.io.FileDescriptor;
360477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport java.io.PrintWriter;
3703cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsevimport java.lang.ref.WeakReference;
380477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
390477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev/**
400477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * A service that used for interaction between Car Service and Instrument Cluster. Car Service may
410477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * provide internal navigation binder interface to Navigation App and all notifications will be
420477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * eventually land in the {@link NavigationRenderer} returned by {@link #getNavigationRenderer()}.
430477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev *
440477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * <p>To extend this class, you must declare the service in your manifest file with
450477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * the {@code android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE} permission
460477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * <pre>
470477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * &lt;service android:name=".MyInstrumentClusterService"
480477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev *          android:permission="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE">
490477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * &lt;/service></pre>
500477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * <p>Also, you will need to register this service in the following configuration file:
510477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * {@code packages/services/Car/service/res/values/config.xml}
520477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev *
530477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * @hide
540477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev */
550477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev@SystemApi
560477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevpublic abstract class InstrumentClusterRenderingService extends Service {
570477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
580477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    private static final String TAG = CarLibLog.TAG_CLUSTER;
590477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
600477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    private RendererBinder mRendererBinder;
610477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
620477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    @Override
630477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    @CallSuper
640477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    public IBinder onBind(Intent intent) {
650477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        if (Log.isLoggable(TAG, Log.DEBUG)) {
660477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            Log.d(TAG, "onBind, intent: " + intent);
670477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
680477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
690477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        if (mRendererBinder == null) {
700477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            mRendererBinder = new RendererBinder(getNavigationRenderer());
710477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
720477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
730477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        return mRendererBinder;
740477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    }
750477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
760477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    /** Returns {@link NavigationRenderer} or null if it's not supported. */
7703cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev    @MainThread
780477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    protected abstract NavigationRenderer getNavigationRenderer();
790477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
8003cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev    /** Called when key event that was addressed to instrument cluster display has been received. */
8103cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev    @MainThread
8203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev    protected void onKeyEvent(KeyEvent keyEvent) {
8303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev    }
8403cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev
850477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    @Override
860477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
870477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        writer.println("**" + getClass().getSimpleName() + "**");
880477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        writer.println("renderer binder: " + mRendererBinder);
89ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev        if (mRendererBinder != null) {
90ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev            writer.println("navigation renderer: " + mRendererBinder.mNavigationRenderer);
91ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev            String owner = "none";
92ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev            if (mRendererBinder.mNavContextOwner != null) {
93ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev                owner = "[uid: " + mRendererBinder.mNavContextOwner.first
94ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev                        + ", pid: " + mRendererBinder.mNavContextOwner.second + "]";
95ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev            }
96ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev            writer.println("navigation focus owner: " + owner);
97ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev        }
980477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    }
990477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1000477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    private class RendererBinder extends IInstrumentCluster.Stub {
1010477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1020477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        private final NavigationRenderer mNavigationRenderer;
10303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        private final UiHandler mUiHandler;
1040477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1050477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        private volatile NavigationBinder mNavigationBinder;
1060477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        private volatile Pair<Integer, Integer> mNavContextOwner;
1070477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1080477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        RendererBinder(NavigationRenderer navigationRenderer) {
1090477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            mNavigationRenderer = navigationRenderer;
11003cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev            mUiHandler = new UiHandler(InstrumentClusterRenderingService.this);
1110477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
1120477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1130477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        @Override
1140477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        public IInstrumentClusterNavigation getNavigationService() throws RemoteException {
1150477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            if (mNavigationBinder == null) {
1160477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                mNavigationBinder = new NavigationBinder(mNavigationRenderer);
1170477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                if (mNavContextOwner != null) {
1180477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                    mNavigationBinder.setNavigationContextOwner(
1190477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                            mNavContextOwner.first, mNavContextOwner.second);
1200477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                }
1210477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            }
1220477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            return mNavigationBinder;
1230477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
1240477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1250477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        @Override
1260477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        public void setNavigationContextOwner(int uid, int pid) throws RemoteException {
1270477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            mNavContextOwner = new Pair<>(uid, pid);
1280477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            if (mNavigationBinder != null) {
1290477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                mNavigationBinder.setNavigationContextOwner(uid, pid);
1300477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            }
1310477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
13203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev
13303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        @Override
13403cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        public void onKeyEvent(KeyEvent keyEvent) throws RemoteException {
13503cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev            mUiHandler.doKeyEvent(keyEvent);
13603cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        }
1370477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    }
1380477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1390477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    private class NavigationBinder extends IInstrumentClusterNavigation.Stub {
1400477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1410477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        private final NavigationRenderer mNavigationRenderer;  // Thread-safe navigation renderer.
1420477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1430477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        private volatile Pair<Integer, Integer> mNavContextOwner;
1440477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1450477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        NavigationBinder(NavigationRenderer navigationRenderer) {
1460477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            mNavigationRenderer = ThreadSafeNavigationRenderer.createFor(
1470477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                    Looper.getMainLooper(),
1480477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                    navigationRenderer);
1490477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
1500477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1510477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        void setNavigationContextOwner(int uid, int pid) {
1520477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            mNavContextOwner = new Pair<>(uid, pid);
1530477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
1540477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1550477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        @Override
1560477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        public void onStartNavigation() throws RemoteException {
1570477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            assertContextOwnership();
1580477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            mNavigationRenderer.onStartNavigation();
1590477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
1600477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1610477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        @Override
1620477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        public void onStopNavigation() throws RemoteException {
1630477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            assertContextOwnership();
1640477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            mNavigationRenderer.onStopNavigation();
1650477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
1660477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1670477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        @Override
1683388e7848f3a30029935463afafe9b8280939127Keun-young Park        public void onNextManeuverChanged(int event, CharSequence eventName, int turnAngle,
1693388e7848f3a30029935463afafe9b8280939127Keun-young Park                int turnNumber, Bitmap image, int turnSide) throws RemoteException {
1700477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            assertContextOwnership();
1713388e7848f3a30029935463afafe9b8280939127Keun-young Park            mNavigationRenderer.onNextTurnChanged(event, eventName, turnAngle, turnNumber,
1720477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                    image, turnSide);
1730477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
1740477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1750477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        @Override
176a928f13d7e41030331afaad33ee62e3772d96541Pavel Maltsev        public void onNextManeuverDistanceChanged(int distanceMeters, int timeSeconds,
177a928f13d7e41030331afaad33ee62e3772d96541Pavel Maltsev                int displayDistanceMillis, int displayDistanceUnit) throws RemoteException {
1780477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            assertContextOwnership();
179a928f13d7e41030331afaad33ee62e3772d96541Pavel Maltsev            mNavigationRenderer.onNextTurnDistanceChanged(distanceMeters, timeSeconds,
180a928f13d7e41030331afaad33ee62e3772d96541Pavel Maltsev                    displayDistanceMillis, displayDistanceUnit);
1810477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
1820477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1830477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        @Override
1840477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        public CarNavigationInstrumentCluster getInstrumentClusterInfo() throws RemoteException {
1850477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            return mNavigationRenderer.getNavigationProperties();
1860477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
1870477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1880477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        private void assertContextOwnership() {
1890477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            int uid = getCallingUid();
1900477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            int pid = getCallingPid();
1910477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev
1920477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            Pair<Integer, Integer> owner = mNavContextOwner;
193ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev            if (owner == null || owner.first != uid || owner.second != pid) {
1940477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                throw new IllegalStateException("Client (uid:" + uid + ", pid: " + pid + ") is"
1950477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                        + "not an owner of APP_CONTEXT_NAVIGATION");
1960477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev            }
1970477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        }
1980477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev    }
19903cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev
20003cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev    private static class UiHandler extends Handler {
20103cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        private static int KEY_EVENT = 0;
20203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        private final WeakReference<InstrumentClusterRenderingService> mRefService;
20303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev
20403cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        UiHandler(InstrumentClusterRenderingService service) {
20503cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev            mRefService = new WeakReference<>(service);
20603cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        }
20703cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev
20803cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        @Override
20903cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        public void handleMessage(Message msg) {
21003cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev            InstrumentClusterRenderingService service = mRefService.get();
21103cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev            if (service == null) {
21203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev                return;
21303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev            }
21403cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev
21503cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev            if (msg.what == KEY_EVENT) {
21603cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev                service.onKeyEvent((KeyEvent) msg.obj);
21703cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev            } else {
21803cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev                throw new IllegalArgumentException("Unexpected message: " + msg);
21903cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev            }
22003cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        }
22103cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev
22203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        void doKeyEvent(KeyEvent event) {
22303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev            sendMessage(obtainMessage(KEY_EVENT, event));
22403cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev        }
22503cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev    }
2260477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev}
227