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 * <service android:name=".MyInstrumentClusterService" 480477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * android:permission="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"> 490477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * </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