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; 21905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.app.ActivityOptions; 220477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.app.Service; 230477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.car.CarLibLog; 24905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport android.car.CarNotConnectedException; 250477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.car.navigation.CarNavigationInstrumentCluster; 260477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.content.Intent; 270477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.graphics.Bitmap; 281fd2ff63ed701ccc8d2f86d6285e09410eedb411Pavel Maltsevimport android.os.Bundle; 2903cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsevimport android.os.Handler; 300477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.os.IBinder; 310477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.os.Looper; 3203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsevimport android.os.Message; 330477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.os.RemoteException; 340477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.util.Log; 350477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport android.util.Pair; 3603cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsevimport android.view.KeyEvent; 370477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 38905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsevimport com.android.internal.annotations.GuardedBy; 39905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev 400477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport java.io.FileDescriptor; 410477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevimport java.io.PrintWriter; 4203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsevimport java.lang.ref.WeakReference; 430477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 440477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev/** 450477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * A service that used for interaction between Car Service and Instrument Cluster. Car Service may 460477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * provide internal navigation binder interface to Navigation App and all notifications will be 470477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * eventually land in the {@link NavigationRenderer} returned by {@link #getNavigationRenderer()}. 480477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * 490477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * <p>To extend this class, you must declare the service in your manifest file with 500477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * the {@code android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE} permission 510477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * <pre> 520477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * <service android:name=".MyInstrumentClusterService" 530477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * android:permission="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"> 540477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * </service></pre> 550477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * <p>Also, you will need to register this service in the following configuration file: 560477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * {@code packages/services/Car/service/res/values/config.xml} 570477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * 580477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * @hide 590477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev */ 600477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev@SystemApi 610477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsevpublic abstract class InstrumentClusterRenderingService extends Service { 620477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 630477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev private static final String TAG = CarLibLog.TAG_CLUSTER; 640477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 650477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev private RendererBinder mRendererBinder; 660477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 67905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev /** @hide */ 68905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev public static final String EXTRA_KEY_CALLBACK_SERVICE = 69905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev "android.car.cluster.IInstrumentClusterCallback"; 70905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev 71905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev private final Object mLock = new Object(); 72905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev @GuardedBy("mLock") 73905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev private IInstrumentClusterCallback mCallback; 74905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev 750477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev @Override 760477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev @CallSuper 770477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev public IBinder onBind(Intent intent) { 780477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev if (Log.isLoggable(TAG, Log.DEBUG)) { 790477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev Log.d(TAG, "onBind, intent: " + intent); 800477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 810477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 82905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev if (intent.getExtras().containsKey(EXTRA_KEY_CALLBACK_SERVICE)) { 83905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev IBinder callbackBinder = intent.getExtras().getBinder(EXTRA_KEY_CALLBACK_SERVICE); 84905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev synchronized (mLock) { 85905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev mCallback = IInstrumentClusterCallback.Stub.asInterface(callbackBinder); 86905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 87905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } else { 88905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev Log.w(TAG, "onBind, no callback in extra!"); 89905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 90905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev 910477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev if (mRendererBinder == null) { 920477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev mRendererBinder = new RendererBinder(getNavigationRenderer()); 930477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 940477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 950477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev return mRendererBinder; 960477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 970477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 980477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev /** Returns {@link NavigationRenderer} or null if it's not supported. */ 9903cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev @MainThread 1000477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev protected abstract NavigationRenderer getNavigationRenderer(); 1010477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 10203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev /** Called when key event that was addressed to instrument cluster display has been received. */ 10303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev @MainThread 10403cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev protected void onKeyEvent(KeyEvent keyEvent) { 10503cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev } 10603cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev 107905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev /** 108905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * 109905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * Sets configuration for activities that should be launched directly in the instrument 110905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * cluster. 111905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * 112905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * @param category category of cluster activity 113905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * @param activityOptions contains information of how to start cluster activity (on what display 114905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * or activity stack. 115905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * 116905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * @hide 117905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev */ 118905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev public void setClusterActivityLaunchOptions(String category, 119905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev ActivityOptions activityOptions) throws CarNotConnectedException { 120905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev IInstrumentClusterCallback cb; 121905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev synchronized (mLock) { 122905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev cb = mCallback; 123905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 124905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev if (cb == null) throw new CarNotConnectedException(); 125905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev try { 126905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev cb.setClusterActivityLaunchOptions(category, activityOptions.toBundle()); 127905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } catch (RemoteException e) { 128905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev throw new CarNotConnectedException(e); 129905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 130905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 131905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev 132905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev /** 133905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * 134905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * @param category cluster activity category, 135905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * see {@link android.car.cluster.CarInstrumentClusterManager} 136905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * @param state pass information about activity state, 137905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * see {@link android.car.cluster.ClusterActivityState} 138905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * @return true if information was sent to Car Service 139905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev * @throws CarNotConnectedException 1404f7c940029f3e53198f6bc980b137f2f4a6312c0Pavel Maltsev * 1414f7c940029f3e53198f6bc980b137f2f4a6312c0Pavel Maltsev * @hide 142905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev */ 143905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev public void setClusterActivityState(String category, Bundle state) 144905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev throws CarNotConnectedException { 145905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev IInstrumentClusterCallback cb; 146905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev synchronized (mLock) { 147905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev cb = mCallback; 148905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 149905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev if (cb == null) throw new CarNotConnectedException(); 150905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev try { 151905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev cb.setClusterActivityState(category, state); 152905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } catch (RemoteException e) { 153905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev throw new CarNotConnectedException(e); 154905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 155905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 156905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev 157905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev 1580477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev @Override 1590477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 1600477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev writer.println("**" + getClass().getSimpleName() + "**"); 1610477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev writer.println("renderer binder: " + mRendererBinder); 162ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev if (mRendererBinder != null) { 163ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev writer.println("navigation renderer: " + mRendererBinder.mNavigationRenderer); 164ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev String owner = "none"; 165905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev synchronized (mLock) { 166905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev if (mRendererBinder.mNavContextOwner != null) { 167905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev owner = "[uid: " + mRendererBinder.mNavContextOwner.first 168905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev + ", pid: " + mRendererBinder.mNavContextOwner.second + "]"; 169905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 170ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev } 171ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev writer.println("navigation focus owner: " + owner); 172ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev } 173905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev IInstrumentClusterCallback cb; 174905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev synchronized (mLock) { 175905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev cb = mCallback; 176905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 177905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev writer.println("callback: " + cb); 1780477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 1790477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 1800477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev private class RendererBinder extends IInstrumentCluster.Stub { 1810477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 1820477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev private final NavigationRenderer mNavigationRenderer; 18303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev private final UiHandler mUiHandler; 1840477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 185905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev @GuardedBy("mLock") 186905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev private NavigationBinder mNavigationBinder; 187905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev @GuardedBy("mLock") 188905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev private Pair<Integer, Integer> mNavContextOwner; 1890477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 1900477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev RendererBinder(NavigationRenderer navigationRenderer) { 1910477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev mNavigationRenderer = navigationRenderer; 19203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev mUiHandler = new UiHandler(InstrumentClusterRenderingService.this); 1930477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 1940477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 1950477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev @Override 1960477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev public IInstrumentClusterNavigation getNavigationService() throws RemoteException { 197905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev synchronized (mLock) { 198905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev if (mNavigationBinder == null) { 199905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev mNavigationBinder = new NavigationBinder(mNavigationRenderer); 200905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev if (mNavContextOwner != null) { 201905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev mNavigationBinder.setNavigationContextOwner( 202905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev mNavContextOwner.first, mNavContextOwner.second); 203905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 2040477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 205905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev return mNavigationBinder; 2060477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2070477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2080477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2090477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev @Override 2100477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev public void setNavigationContextOwner(int uid, int pid) throws RemoteException { 211905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev synchronized (mLock) { 212905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev mNavContextOwner = new Pair<>(uid, pid); 213905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev if (mNavigationBinder != null) { 214905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev mNavigationBinder.setNavigationContextOwner(uid, pid); 215905968cf95d4c8608d6d9351b5dd10fe994a1220Pavel Maltsev } 2160477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2170477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 21803cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev 21903cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev @Override 22003cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev public void onKeyEvent(KeyEvent keyEvent) throws RemoteException { 22103cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev mUiHandler.doKeyEvent(keyEvent); 22203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev } 2230477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2240477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2250477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev private class NavigationBinder extends IInstrumentClusterNavigation.Stub { 2260477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2270477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev private final NavigationRenderer mNavigationRenderer; // Thread-safe navigation renderer. 2280477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2290477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev private volatile Pair<Integer, Integer> mNavContextOwner; 2300477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2310477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev NavigationBinder(NavigationRenderer navigationRenderer) { 2320477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev mNavigationRenderer = ThreadSafeNavigationRenderer.createFor( 2330477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev Looper.getMainLooper(), 2340477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev navigationRenderer); 2350477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2360477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2370477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev void setNavigationContextOwner(int uid, int pid) { 2380477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev mNavContextOwner = new Pair<>(uid, pid); 2390477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2400477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2410477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev @Override 2420477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev public void onStartNavigation() throws RemoteException { 2430477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev assertContextOwnership(); 2440477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev mNavigationRenderer.onStartNavigation(); 2450477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2460477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2470477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev @Override 2480477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev public void onStopNavigation() throws RemoteException { 2490477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev assertContextOwnership(); 2500477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev mNavigationRenderer.onStopNavigation(); 2510477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2520477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2530477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev @Override 2543388e7848f3a30029935463afafe9b8280939127Keun-young Park public void onNextManeuverChanged(int event, CharSequence eventName, int turnAngle, 2553388e7848f3a30029935463afafe9b8280939127Keun-young Park int turnNumber, Bitmap image, int turnSide) throws RemoteException { 2560477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev assertContextOwnership(); 2573388e7848f3a30029935463afafe9b8280939127Keun-young Park mNavigationRenderer.onNextTurnChanged(event, eventName, turnAngle, turnNumber, 2580477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev image, turnSide); 2590477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2600477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2610477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev @Override 262a928f13d7e41030331afaad33ee62e3772d96541Pavel Maltsev public void onNextManeuverDistanceChanged(int distanceMeters, int timeSeconds, 263a928f13d7e41030331afaad33ee62e3772d96541Pavel Maltsev int displayDistanceMillis, int displayDistanceUnit) throws RemoteException { 2640477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev assertContextOwnership(); 265a928f13d7e41030331afaad33ee62e3772d96541Pavel Maltsev mNavigationRenderer.onNextTurnDistanceChanged(distanceMeters, timeSeconds, 266a928f13d7e41030331afaad33ee62e3772d96541Pavel Maltsev displayDistanceMillis, displayDistanceUnit); 2670477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2680477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2690477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev @Override 2701fd2ff63ed701ccc8d2f86d6285e09410eedb411Pavel Maltsev public void onEvent(int eventType, Bundle bundle) throws RemoteException { 2711fd2ff63ed701ccc8d2f86d6285e09410eedb411Pavel Maltsev assertContextOwnership(); 2721fd2ff63ed701ccc8d2f86d6285e09410eedb411Pavel Maltsev mNavigationRenderer.onEvent(eventType, bundle); 2731fd2ff63ed701ccc8d2f86d6285e09410eedb411Pavel Maltsev } 2741fd2ff63ed701ccc8d2f86d6285e09410eedb411Pavel Maltsev 2751fd2ff63ed701ccc8d2f86d6285e09410eedb411Pavel Maltsev @Override 2760477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev public CarNavigationInstrumentCluster getInstrumentClusterInfo() throws RemoteException { 2770477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev return mNavigationRenderer.getNavigationProperties(); 2780477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2790477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2800477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev private void assertContextOwnership() { 2810477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev int uid = getCallingUid(); 2820477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev int pid = getCallingPid(); 2830477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev 2840477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev Pair<Integer, Integer> owner = mNavContextOwner; 285ffb3fb5029c2360cd03478dadac6c87f472e2875Pavel Maltsev if (owner == null || owner.first != uid || owner.second != pid) { 2860477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev throw new IllegalStateException("Client (uid:" + uid + ", pid: " + pid + ") is" 2870477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev + "not an owner of APP_CONTEXT_NAVIGATION"); 2880477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2890477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 2900477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev } 29103cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev 29203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev private static class UiHandler extends Handler { 29303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev private static int KEY_EVENT = 0; 29403cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev private final WeakReference<InstrumentClusterRenderingService> mRefService; 29503cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev 29603cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev UiHandler(InstrumentClusterRenderingService service) { 29703cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev mRefService = new WeakReference<>(service); 29803cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev } 29903cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev 30003cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev @Override 30103cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev public void handleMessage(Message msg) { 30203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev InstrumentClusterRenderingService service = mRefService.get(); 30303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev if (service == null) { 30403cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev return; 30503cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev } 30603cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev 30703cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev if (msg.what == KEY_EVENT) { 30803cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev service.onKeyEvent((KeyEvent) msg.obj); 30903cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev } else { 31003cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev throw new IllegalArgumentException("Unexpected message: " + msg); 31103cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev } 31203cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev } 31303cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev 31403cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev void doKeyEvent(KeyEvent event) { 31503cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev sendMessage(obtainMessage(KEY_EVENT, event)); 31603cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev } 31703cf60ce1ac0c87d137f93aeaac4b3062cdf839cPavel Maltsev } 3180477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev} 319