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 * &lt;service android:name=".MyInstrumentClusterService"
530477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev *          android:permission="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE">
540477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev * &lt;/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