1ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung/*
2ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * Copyright (C) 2015 The Android Open Source Project
3ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung *
4ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * Licensed under the Apache License, Version 2.0 (the "License");
5ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * you may not use this file except in compliance with the License.
6ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * You may obtain a copy of the License at
7ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung *
8ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung *      http://www.apache.org/licenses/LICENSE-2.0
9ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung *
10ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * Unless required by applicable law or agreed to in writing, software
11ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * distributed under the License is distributed on an "AS IS" BASIS,
12ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * See the License for the specific language governing permissions and
14ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung * limitations under the License.
15ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung */
16ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
17e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Parkpackage android.car;
18ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
19e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Parkimport android.annotation.IntDef;
20e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Parkimport android.annotation.Nullable;
21e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Parkimport android.annotation.SystemApi;
22e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortesimport android.car.annotation.FutureFeature;
236e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkivimport android.car.content.pm.CarPackageManager;
245c56d2a3a5bc4ef5b46a58fa56b7f4a657b0827eEnrico Granataimport android.car.hardware.CarDiagnosticManager;
256e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkivimport android.car.hardware.CarSensorManager;
26634e1ff49c62c32c8227ec5092743de3caca790cPavel Maltsevimport android.car.hardware.CarVendorExtensionManager;
270d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsevimport android.car.hardware.cabin.CarCabinManager;
286e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkivimport android.car.hardware.hvac.CarHvacManager;
296e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkivimport android.car.hardware.radio.CarRadioManager;
306e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkivimport android.car.media.CarAudioManager;
313388e7848f3a30029935463afafe9b8280939127Keun-young Parkimport android.car.navigation.CarNavigationStatusManager;
326e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkivimport android.car.test.CarTestManagerBinderWrapper;
33a7d8ed1681d297bdda8345c1598c7b9a388599beAntonio Cortesimport android.car.vms.VmsSubscriberManager;
34ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport android.content.ComponentName;
35ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport android.content.Context;
36e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Parkimport android.content.Intent;
37e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Parkimport android.content.ServiceConnection;
38ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport android.content.pm.PackageManager;
396b19769ee8cfbe0960d05ecfc01f73d08040784fkeunyoungimport android.os.Handler;
40ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport android.os.IBinder;
41ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport android.os.Looper;
42ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport android.os.RemoteException;
4344241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Parkimport android.os.UserHandle;
44ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport android.util.Log;
45ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
46c52d5f9f6190cf9a44dd6dfd3bc92386fbf023b3Antonio Cortesimport com.android.car.internal.FeatureConfiguration;
47c52d5f9f6190cf9a44dd6dfd3bc92386fbf023b3Antonio Cortesimport com.android.car.internal.FeatureUtil;
48e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Parkimport com.android.internal.annotations.GuardedBy;
49e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
50ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport java.lang.annotation.Retention;
51ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport java.lang.annotation.RetentionPolicy;
52ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoungimport java.util.HashMap;
536b19769ee8cfbe0960d05ecfc01f73d08040784fkeunyoung
54ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung/**
55e4c731ea3ed22615783efb02818b0b3d184bba33Jason Tholstrup *   Top level car API for embedded Android Auto deployments.
56e4c731ea3ed22615783efb02818b0b3d184bba33Jason Tholstrup *   This API works only for devices with {@link PackageManager#FEATURE_AUTOMOTIVE}
57e4c731ea3ed22615783efb02818b0b3d184bba33Jason Tholstrup *   Calling this API on a device with no such feature will lead to an exception.
58ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung */
594cf6911619b9fe6ffeba7afeb05299aab165f184Keun-young Parkpublic final class Car {
60ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
61f521fd7b917a63c240802c7f841fc04c315573d0Keun-young Park    /**
6212cfa0d0d909df96c501546eec83bfa09515e3f8Keun-young Park     * Represent the version of Car API. This is only updated when there is API change.
6312cfa0d0d909df96c501546eec83bfa09515e3f8Keun-young Park     * 1 : N
6412cfa0d0d909df96c501546eec83bfa09515e3f8Keun-young Park     * 2 : O
65f521fd7b917a63c240802c7f841fc04c315573d0Keun-young Park     */
6612cfa0d0d909df96c501546eec83bfa09515e3f8Keun-young Park    public static final int VERSION = 2;
67f521fd7b917a63c240802c7f841fc04c315573d0Keun-young Park
68a3b28d81e0c8df531ac704f9e649e38ea90483d2keunyoung    /** Service name for {@link CarSensorManager}, to be used in {@link #getCarManager(String)}. */
69ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    public static final String SENSOR_SERVICE = "sensor";
70ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
71a3b28d81e0c8df531ac704f9e649e38ea90483d2keunyoung    /** Service name for {@link CarInfoManager}, to be used in {@link #getCarManager(String)}. */
72a3b28d81e0c8df531ac704f9e649e38ea90483d2keunyoung    public static final String INFO_SERVICE = "info";
73a3b28d81e0c8df531ac704f9e649e38ea90483d2keunyoung
743ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup    /** Service name for {@link CarAppFocusManager}. */
7546371473c416415fb6bcb8db85686669c3d65af6Vitalii Tomkiv    public static final String APP_FOCUS_SERVICE = "app_focus";
76a74b9caa2fb6435f1c01c5e8766b89235c4e3d5akeunyoung
777a948e54331cccf96f178ab426cb7810472c2dc8Pavel Maltsev    /** Service name for {@link CarPackageManager} */
7845fdcbaab5699d7d8153bfda058d0eea2049c8b8Keun-young Park    public static final String PACKAGE_SERVICE = "package";
7945fdcbaab5699d7d8153bfda058d0eea2049c8b8Keun-young Park
805672e85bdf82f6a2350afb942dfe17b7c699af87Keun-young Park    /** Service name for {@link CarAudioManager} */
815672e85bdf82f6a2350afb942dfe17b7c699af87Keun-young Park    public static final String AUDIO_SERVICE = "audio";
827a948e54331cccf96f178ab426cb7810472c2dc8Pavel Maltsev    /**
833388e7848f3a30029935463afafe9b8280939127Keun-young Park     * Service name for {@link CarNavigationStatusManager}
847a948e54331cccf96f178ab426cb7810472c2dc8Pavel Maltsev     * @hide
857a948e54331cccf96f178ab426cb7810472c2dc8Pavel Maltsev     */
867a948e54331cccf96f178ab426cb7810472c2dc8Pavel Maltsev    public static final String CAR_NAVIGATION_SERVICE = "car_navigation_service";
877a948e54331cccf96f178ab426cb7810472c2dc8Pavel Maltsev
88280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv    /**
89280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * @hide
90280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     */
91e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    @SystemApi
9243c04a7c87404d078db60e09d2da0061d72357c2Steve Paik    public static final String CABIN_SERVICE = "cabin";
9343c04a7c87404d078db60e09d2da0061d72357c2Steve Paik
9443c04a7c87404d078db60e09d2da0061d72357c2Steve Paik    /**
9543c04a7c87404d078db60e09d2da0061d72357c2Steve Paik     * @hide
9643c04a7c87404d078db60e09d2da0061d72357c2Steve Paik     */
975c56d2a3a5bc4ef5b46a58fa56b7f4a657b0827eEnrico Granata    public static final String DIAGNOSTIC_SERVICE = "diagnostic";
985c56d2a3a5bc4ef5b46a58fa56b7f4a657b0827eEnrico Granata
995c56d2a3a5bc4ef5b46a58fa56b7f4a657b0827eEnrico Granata    /**
1005c56d2a3a5bc4ef5b46a58fa56b7f4a657b0827eEnrico Granata     * @hide
1015c56d2a3a5bc4ef5b46a58fa56b7f4a657b0827eEnrico Granata     */
1025c56d2a3a5bc4ef5b46a58fa56b7f4a657b0827eEnrico Granata    @SystemApi
103e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static final String RADIO_SERVICE = "radio";
104ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
105280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv    /**
106280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * @hide
107280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     */
108e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    @SystemApi
109e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static final String HVAC_SERVICE = "hvac";
110e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
111280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv    /**
112280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * @hide
113280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     */
1146e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkiv    @SystemApi
1156e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkiv    public static final String PROJECTION_SERVICE = "projection";
1166e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkiv
117e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    /**
118634e1ff49c62c32c8227ec5092743de3caca790cPavel Maltsev     * @hide
119634e1ff49c62c32c8227ec5092743de3caca790cPavel Maltsev     */
120634e1ff49c62c32c8227ec5092743de3caca790cPavel Maltsev    @SystemApi
121634e1ff49c62c32c8227ec5092743de3caca790cPavel Maltsev    public static final String VENDOR_EXTENSION_SERVICE = "vendor_extension";
122634e1ff49c62c32c8227ec5092743de3caca790cPavel Maltsev
123634e1ff49c62c32c8227ec5092743de3caca790cPavel Maltsev    /**
124e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes     * @FutureFeature Cannot drop due to usage in non-flag protected place.
125e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes     * @hide
126e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes     */
127e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes    @SystemApi
128e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes    public static final String VMS_SUBSCRIBER_SERVICE = "vehicle_map_subscriber_service";
129e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes
130e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes    /**
131e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park     * Service for testing. This is system app only feature.
132e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park     * Service name for {@link CarTestManager}, to be used in {@link #getCarManager(String)}.
133e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park     * @hide
134e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park     */
135e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    @SystemApi
136e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static final String TEST_SERVICE = "car-service-test";
137ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
138ce4ffd95d6883b28756e5b02ae45a06013bd6c38Pavel Maltsev    /** Permission necessary to access car's mileage information. */
139e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static final String PERMISSION_MILEAGE = "android.car.permission.CAR_MILEAGE";
140e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
141ce4ffd95d6883b28756e5b02ae45a06013bd6c38Pavel Maltsev    /** Permission necessary to access car's fuel level. */
142e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static final String PERMISSION_FUEL = "android.car.permission.CAR_FUEL";
143e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
144ce4ffd95d6883b28756e5b02ae45a06013bd6c38Pavel Maltsev    /** Permission necessary to access car's speed. */
145e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static final String PERMISSION_SPEED = "android.car.permission.CAR_SPEED";
146e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
147ce4ffd95d6883b28756e5b02ae45a06013bd6c38Pavel Maltsev    /**
148c4d442f4a0d3acf90b1c7a1dd7c222a8f32a193fYao Chen     * Permission necessary to change car audio volume through {@link CarAudioManager}.
149c4d442f4a0d3acf90b1c7a1dd7c222a8f32a193fYao Chen     */
150c4d442f4a0d3acf90b1c7a1dd7c222a8f32a193fYao Chen    public static final String PERMISSION_CAR_CONTROL_AUDIO_VOLUME =
151c4d442f4a0d3acf90b1c7a1dd7c222a8f32a193fYao Chen            "android.car.permission.CAR_CONTROL_AUDIO_VOLUME";
152c4d442f4a0d3acf90b1c7a1dd7c222a8f32a193fYao Chen
153c4d442f4a0d3acf90b1c7a1dd7c222a8f32a193fYao Chen    /**
154fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park     * Permission necessary to change car audio settings through {@link CarAudioManager}.
155fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park     * @hide
156fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park     */
157fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    public static final String PERMISSION_CAR_CONTROL_AUDIO_SETTINGS =
158fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            "android.car.permission.CAR_CONTROL_AUDIO_SETTINGS";
159fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
160fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    /**
1613388e7848f3a30029935463afafe9b8280939127Keun-young Park     * Permission necessary to use {@link CarNavigationStatusManager}.
162ce4ffd95d6883b28756e5b02ae45a06013bd6c38Pavel Maltsev     * @hide
163ce4ffd95d6883b28756e5b02ae45a06013bd6c38Pavel Maltsev     */
164ce4ffd95d6883b28756e5b02ae45a06013bd6c38Pavel Maltsev    public static final String PERMISSION_CAR_NAVIGATION_MANAGER =
165e31a8b24afe58bfc924fab7b66c9e48b9ef8e884Keun-young Park            "android.car.permission.CAR_NAVIGATION_MANAGER";
166ce4ffd95d6883b28756e5b02ae45a06013bd6c38Pavel Maltsev
167280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv    /**
168280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * Permission necessary to access car specific communication channel.
169280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * @hide
170280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     */
171e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    @SystemApi
172ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    public static final String PERMISSION_VENDOR_EXTENSION =
173e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            "android.car.permission.CAR_VENDOR_EXTENSION";
174e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
175280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv    /**
176280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * @hide
177280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     */
178e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    @SystemApi
1794aeb4bf0c56588be65264c324bbaaa545ad6714cKeun-young Park    public static final String PERMISSION_CONTROL_APP_BLOCKING =
180e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            "android.car.permission.CONTROL_APP_BLOCKING";
181ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
182280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv    /**
18343c04a7c87404d078db60e09d2da0061d72357c2Steve Paik     * Permission necessary to access Car Cabin APIs.
18443c04a7c87404d078db60e09d2da0061d72357c2Steve Paik     * @hide
18543c04a7c87404d078db60e09d2da0061d72357c2Steve Paik     */
18643c04a7c87404d078db60e09d2da0061d72357c2Steve Paik    @SystemApi
18743c04a7c87404d078db60e09d2da0061d72357c2Steve Paik    public static final String PERMISSION_CAR_CABIN = "android.car.permission.CAR_CABIN";
18843c04a7c87404d078db60e09d2da0061d72357c2Steve Paik
18943c04a7c87404d078db60e09d2da0061d72357c2Steve Paik    /**
190280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * Permission necessary to access Car HVAC APIs.
191280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * @hide
192280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     */
193e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    @SystemApi
194e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static final String PERMISSION_CAR_HVAC = "android.car.permission.CAR_HVAC";
195ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
196280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv    /**
197280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * Permission necessary to access Car RADIO system APIs.
198280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * @hide
199280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     */
200e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    @SystemApi
201e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static final String PERMISSION_CAR_RADIO = "android.car.permission.CAR_RADIO";
202ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
203b13dbe470108846d1c04494c5c0d2bf3cd9b8054Jason Tholstrup
204280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv    /**
205b13dbe470108846d1c04494c5c0d2bf3cd9b8054Jason Tholstrup     * Permission necessary to access Car PROJECTION system APIs.
206280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * @hide
207280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     */
2086e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkiv    @SystemApi
2096e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkiv    public static final String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
2106e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkiv
211280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv    /**
212280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * Permission necessary to mock vehicle hal for testing.
213280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     * @hide
2140d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev     * @deprecated mocking vehicle HAL in car service is no longer supported.
215280b5721254e5ac974404e02e7589f17f560d1f9Vitalii Tomkiv     */
216e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    @SystemApi
217e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static final String PERMISSION_MOCK_VEHICLE_HAL =
218e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            "android.car.permission.CAR_MOCK_VEHICLE_HAL";
219e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
2201ecdd6ca75fdf8ff62105630664de5125e29676bPavel Maltsev    /**
2210d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev     * Permission necessary to access CarTestService.
2221ecdd6ca75fdf8ff62105630664de5125e29676bPavel Maltsev     * @hide
2231ecdd6ca75fdf8ff62105630664de5125e29676bPavel Maltsev     */
2240d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    @SystemApi
2250d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    public static final String PERMISSION_CAR_TEST_SERVICE =
2260d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            "android.car.permission.CAR_TEST_SERVICE";
2270d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev
228e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes    /**
2296b3544cf13ee99d6704216c96d40f89aff9bdc2bAntonio Cortes     * Permissions necessary to access VMS publisher APIs.
2306b3544cf13ee99d6704216c96d40f89aff9bdc2bAntonio Cortes     *
2316b3544cf13ee99d6704216c96d40f89aff9bdc2bAntonio Cortes     * @hide
2326b3544cf13ee99d6704216c96d40f89aff9bdc2bAntonio Cortes     */
2336b3544cf13ee99d6704216c96d40f89aff9bdc2bAntonio Cortes    @FutureFeature
2346b3544cf13ee99d6704216c96d40f89aff9bdc2bAntonio Cortes    @SystemApi
2356b3544cf13ee99d6704216c96d40f89aff9bdc2bAntonio Cortes    public static final String PERMISSION_VMS_PUBLISHER = "android.car.permission.VMS_PUBLISHER";
2366b3544cf13ee99d6704216c96d40f89aff9bdc2bAntonio Cortes
2376b3544cf13ee99d6704216c96d40f89aff9bdc2bAntonio Cortes    /**
2386b3544cf13ee99d6704216c96d40f89aff9bdc2bAntonio Cortes     * Permissions necessary to access VMS subscriber APIs.
2396b3544cf13ee99d6704216c96d40f89aff9bdc2bAntonio Cortes     *
240e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes     * @hide
241e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes     */
242e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes    @FutureFeature
243e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes    @SystemApi
244e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes    public static final String PERMISSION_VMS_SUBSCRIBER = "android.car.permission.VMS_SUBSCRIBER";
245e4619c7bdd549833cb795b74e438a7d1f3caa1b5Antonio Cortes
2463c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata    /**
2473c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata     * Permissions necessary to read diagnostic information.
2483c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata     *
2493c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata     * @hide
2503c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata     */
2513c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata    @FutureFeature
2523c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata    public static final String PERMISSION_CAR_DIAGNOSTIC_READ = "android.car.permission.DIAGNOSTIC_READ";
2533c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata
2543c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata    /**
2553c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata     * Permissions necessary to clear diagnostic information.
2563c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata     *
2573c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata     * @hide
2583c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata     */
2593c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata    @FutureFeature
2603c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata    public static final String PERMISSION_CAR_DIAGNOSTIC_CLEAR = "android.car.permission.DIAGNOSTIC_CLEAR";
2613c7a66693e28acaa82d3c9ff2ed99712270c889fEnrico Granata
2620d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    /** Type of car connection: platform runs directly in car. */
2630d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    public static final int CONNECTION_TYPE_EMBEDDED = 5;
264e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
265e4c731ea3ed22615783efb02818b0b3d184bba33Jason Tholstrup
266e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    /** @hide */
2670d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    @IntDef({CONNECTION_TYPE_EMBEDDED})
268e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    @Retention(RetentionPolicy.SOURCE)
269e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public @interface ConnectionType {}
270ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
2713cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal    /**
2723cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     * CarXyzService throws IllegalStateException with this message is re-thrown as
2733cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     * {@link CarNotConnectedException}.
2743cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     *
2753cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     * @hide
2763cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     */
2773cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal    public static final String CAR_NOT_CONNECTED_EXCEPTION_MSG = "CarNotConnected";
2783cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal
279e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    /** @hide */
280e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static final String CAR_SERVICE_INTERFACE_NAME = "android.car.ICar";
281e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
282e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    private static final String CAR_SERVICE_PACKAGE = "com.android.car";
283e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
28444241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park    private static final String CAR_SERVICE_CLASS = "com.android.car.CarService";
28544241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park
28644241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park    private static final long CAR_SERVICE_BIND_RETRY_INTERVAL_MS = 500;
28744241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park    private static final long CAR_SERVICE_BIND_MAX_RETRY = 20;
28844241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park
289ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private final Context mContext;
290ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    @GuardedBy("this")
291ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private ICar mService;
2920d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    private final boolean mOwnsService;
293ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private static final int STATE_DISCONNECTED = 0;
294ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private static final int STATE_CONNECTING = 1;
295ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private static final int STATE_CONNECTED = 2;
296ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    @GuardedBy("this")
297ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private int mConnectionState;
29844241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park    @GuardedBy("this")
29944241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park    private int mConnectionRetryCount;
30044241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park
30144241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park    private final Runnable mConnectionRetryRunnable = new Runnable() {
30244241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park        @Override
30344241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park        public void run() {
30444241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park            startCarService();
30544241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park        }
30644241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park    };
30744241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park
30844241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park    private final Runnable mConnectionRetryFailedRunnable = new Runnable() {
30944241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park        @Override
31044241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park        public void run() {
31144241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park            mServiceConnectionListener.onServiceDisconnected(new ComponentName(CAR_SERVICE_PACKAGE,
31244241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park                    CAR_SERVICE_CLASS));
31344241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park        }
31444241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park    };
315ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
316e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    private final ServiceConnection mServiceConnectionListener =
317e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            new ServiceConnection () {
318ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        public void onServiceConnected(ComponentName name, IBinder service) {
3191ab8e18e01d8063821bee0bf641a365224c7e1eekeunyoung            synchronized (Car.this) {
320ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                mService = ICar.Stub.asInterface(service);
321ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                mConnectionState = STATE_CONNECTED;
322ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            }
323ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            mServiceConnectionListenerClient.onServiceConnected(name, service);
324ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        }
325ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
326ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        public void onServiceDisconnected(ComponentName name) {
3271ab8e18e01d8063821bee0bf641a365224c7e1eekeunyoung            synchronized (Car.this) {
328ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                mService = null;
329ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                if (mConnectionState  == STATE_DISCONNECTED) {
330ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                    return;
331ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                }
332cc449f7941456a0133ff8a4b2e49737f0936c1d0keunyoung                mConnectionState = STATE_DISCONNECTED;
333ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            }
334e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            // unbind explicitly here.
335e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            disconnect();
336ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            mServiceConnectionListenerClient.onServiceDisconnected(name);
337ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        }
338ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    };
339ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
340e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    private final ServiceConnection mServiceConnectionListenerClient;
341ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private final Object mCarManagerLock = new Object();
342ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    @GuardedBy("mCarManagerLock")
343ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private final HashMap<String, CarManagerBase> mServiceMap = new HashMap<>();
3446b19769ee8cfbe0960d05ecfc01f73d08040784fkeunyoung
3456b19769ee8cfbe0960d05ecfc01f73d08040784fkeunyoung    /** Handler for generic event dispatching. */
3466b19769ee8cfbe0960d05ecfc01f73d08040784fkeunyoung    private final Handler mEventHandler;
3476b19769ee8cfbe0960d05ecfc01f73d08040784fkeunyoung
3483ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup    private final Handler mMainThreadEventHandler;
34944241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park
3501ab8e18e01d8063821bee0bf641a365224c7e1eekeunyoung    /**
3518de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev     * A factory method that creates Car instance for all Car API access.
352ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * @param context
353e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park     * @param serviceConnectionListener listener for monitoring service connection.
3543ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup     * @param handler the handler on which the callback should execute, or null to execute on the
3553ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup     * service's main thread. Note: the service connection listener will be always on the main
3563ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup     * thread regardless of the handler given.
3578de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev     * @return Car instance if system is in car environment and returns {@code null} otherwise.
358ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     */
359e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static Car createCar(Context context, ServiceConnection serviceConnectionListener,
3603ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup            @Nullable Handler handler) {
361e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park        if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
362e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            Log.e(CarLibLog.TAG_CAR, "FEATURE_AUTOMOTIVE not declared while android.car is used");
363e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            return null;
364e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park        }
3658de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev        try {
3663ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup          return new Car(context, serviceConnectionListener, handler);
3678de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev        } catch (IllegalArgumentException e) {
3688de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev          // Expected when car service loader is not available.
3698de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev        }
3708de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev        return null;
3718de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev    }
3728de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev
3738de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev    /**
3748de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev     * A factory method that creates Car instance for all Car API access using main thread {@code
3758de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev     * Looper}.
3768de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev     *
3773ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup     * @see #createCar(Context, ServiceConnection, Handler)
3788de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev     */
379e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public static Car createCar(Context context, ServiceConnection serviceConnectionListener) {
3808de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev      return createCar(context, serviceConnectionListener, null);
3818de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev    }
3828de993354f1a8c30880b535cf8b80fee10c4e882Pavel Maltsev
383e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    private Car(Context context, ServiceConnection serviceConnectionListener,
3843ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup            @Nullable Handler handler) {
385ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        mContext = context;
3863ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup        mEventHandler = determineEventHandler(handler);
387224220701b9c22ebcfc7dc532714839dca202bb3Yao Chen        mMainThreadEventHandler = determineMainThreadEventHandler(mEventHandler);
3883ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup
3893ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup        mService = null;
3900d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        mOwnsService = true;
391ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        mServiceConnectionListenerClient = serviceConnectionListener;
392ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
393ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
3943ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup
395ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    /**
3960d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev     * Car constructor when ICar binder is already available.
397ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * @hide
398ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     */
3993ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup    public Car(Context context, ICar service, @Nullable Handler handler) {
400ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        mContext = context;
4013ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup        mEventHandler = determineEventHandler(handler);
402f4f07bf04563b9ad25ff9cdfc96f40790f155e41Keun-young Park        mMainThreadEventHandler = determineMainThreadEventHandler(mEventHandler);
4033ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup
404ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        mService = service;
4050d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        mOwnsService = false;
406ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        mConnectionState = STATE_CONNECTED;
407ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        mServiceConnectionListenerClient = null;
408ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
409ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
4103ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup    private static Handler determineMainThreadEventHandler(Handler eventHandler) {
4113ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup        Looper mainLooper = Looper.getMainLooper();
4123ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup        return (eventHandler.getLooper() == mainLooper) ? eventHandler : new Handler(mainLooper);
4133ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup    }
4143ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup
4153ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup    private static Handler determineEventHandler(@Nullable Handler handler) {
4163ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup        if (handler == null) {
417f4f07bf04563b9ad25ff9cdfc96f40790f155e41Keun-young Park            Looper looper = Looper.getMainLooper();
4183ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup            handler = new Handler(looper);
4193ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup        }
4203ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup        return handler;
4213ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup    }
4223ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup
423ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    /**
424ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * Connect to car service. This can be called while it is disconnected.
425ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * @throws IllegalStateException If connection is still on-going from previous
426ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     *         connect call or it is already connected
427ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     */
428ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    public void connect() throws IllegalStateException {
429ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        synchronized (this) {
430ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            if (mConnectionState != STATE_DISCONNECTED) {
431ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                throw new IllegalStateException("already connected or connecting");
432ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            }
433ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            mConnectionState = STATE_CONNECTING;
434e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            startCarService();
435ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        }
436ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
437ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
438ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    /**
439ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * Disconnect from car service. This can be called while disconnected. Once disconnect is
440ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * called, all Car*Managers from this instance becomes invalid, and
441ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * {@link Car#getCarManager(String)} will return different instance if it is connected again.
442ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     */
443ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    public void disconnect() {
444ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        synchronized (this) {
445ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            if (mConnectionState == STATE_DISCONNECTED) {
446ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                return;
447ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            }
44844241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park            mEventHandler.removeCallbacks(mConnectionRetryRunnable);
4493ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup            mMainThreadEventHandler.removeCallbacks(mConnectionRetryFailedRunnable);
45044241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park            mConnectionRetryCount = 0;
451ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            tearDownCarManagers();
452ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            mService = null;
453ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            mConnectionState = STATE_DISCONNECTED;
4540d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev
4550d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            if (mOwnsService) {
4560d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev                mContext.unbindService(mServiceConnectionListener);
4570d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            }
458ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        }
459ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
460ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
461ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    /**
462ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * Tells if it is connected to the service or not. This will return false if it is still
463ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * connecting.
464ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * @return
465ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     */
466ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    public boolean isConnected() {
467ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        synchronized (this) {
468ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            return mService != null;
469ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        }
470ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
471ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
472ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    /**
473ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * Tells if this instance is already connecting to car service or not.
474ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * @return
475ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     */
476ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    public boolean isConnecting() {
477ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        synchronized (this) {
478ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            return mConnectionState == STATE_CONNECTING;
479ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        }
480ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
481ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
482ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    /**
483ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * Get car specific service as in {@link Context#getSystemService(String)}. Returned
484ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * {@link Object} should be type-casted to the desired service.
485ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * For example, to get sensor service,
486ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * SensorManagerService sensorManagerService = car.getCarManager(Car.SENSOR_SERVICE);
487ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * @param serviceName Name of service that should be created like {@link #SENSOR_SERVICE}.
488ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * @return Matching service manager or null if there is no such service.
489d72b53500006e84b0c69e650878267c693c164a3Jason Tholstrup     * @throws CarNotConnectedException if the connection to the car service has been lost.
490ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     */
491235f8acd3cf83079ecd0f3e1b8368b0c9886de82Vitalii Tomkiv    public Object getCarManager(String serviceName) throws CarNotConnectedException {
4920477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev        CarManagerBase manager;
4931ab8e18e01d8063821bee0bf641a365224c7e1eekeunyoung        ICar service = getICarOrThrow();
494ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        synchronized (mCarManagerLock) {
495ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            manager = mServiceMap.get(serviceName);
496ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            if (manager == null) {
497ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                try {
4981ab8e18e01d8063821bee0bf641a365224c7e1eekeunyoung                    IBinder binder = service.getCarService(serviceName);
499ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                    if (binder == null) {
500ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                        Log.w(CarLibLog.TAG_CAR, "getCarManager could not get binder for service:" +
501ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                                serviceName);
502ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                        return null;
503ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                    }
504e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                    manager = createCarManager(serviceName, binder);
505ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                    if (manager == null) {
506ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                        Log.w(CarLibLog.TAG_CAR,
507ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                                "getCarManager could not create manager for service:" +
5080477e29bb17ee8ec99acfa5fa966889cd45ebf34Pavel Maltsev                                        serviceName);
509ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                        return null;
510ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                    }
511ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                    mServiceMap.put(serviceName, manager);
512ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                } catch (RemoteException e) {
513e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                    handleRemoteException(e);
514ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                }
515ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            }
516ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        }
517ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        return manager;
518ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
519ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
520ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    /**
521ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * Return the type of currently connected car.
522ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     * @return
523ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung     */
524ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    @ConnectionType
525e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    public int getCarConnectionType() {
526e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park        return CONNECTION_TYPE_EMBEDDED;
527ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
528ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
5293cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal    /**
5303cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     * IllegalStateException from XyzCarService with special message is re-thrown as a different
5313cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     * exception. If the IllegalStateException is not understood then this message will throw the
5323cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     * original exception.
5333cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     *
5343cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     * @param e exception from XyzCarService.
535d72b53500006e84b0c69e650878267c693c164a3Jason Tholstrup     * @throws CarNotConnectedException if the connection to the car service has been lost.
5363cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     * @hide
5373cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal     */
5383cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal    public static void checkCarNotConnectedExceptionFromCarService(
5393cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal            IllegalStateException e) throws CarNotConnectedException, IllegalStateException {
5403cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal        String message = e.getMessage();
54177ac6cf7366599d48d242205bcf5a67bcc633980Keun-young Park        if (CAR_NOT_CONNECTED_EXCEPTION_MSG.equals(message)) {
5423cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal            throw new CarNotConnectedException();
5433cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal        } else {
5443cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal            throw e;
5453cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal        }
5463cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal    }
5473cf096ae0d992d22cfba1b0711af2211c511a9feSanket Agarwal
548150d8de43e71a624106e90bcc04067414c42ef18Keun-young Park    /** @hide */
549150d8de43e71a624106e90bcc04067414c42ef18Keun-young Park    public static void hideCarNotConnectedExceptionFromCarService(
550150d8de43e71a624106e90bcc04067414c42ef18Keun-young Park            IllegalStateException e) throws IllegalStateException {
551150d8de43e71a624106e90bcc04067414c42ef18Keun-young Park        String message = e.getMessage();
552150d8de43e71a624106e90bcc04067414c42ef18Keun-young Park        if (CAR_NOT_CONNECTED_EXCEPTION_MSG.equals(message)) {
553150d8de43e71a624106e90bcc04067414c42ef18Keun-young Park            return; //ignore
554150d8de43e71a624106e90bcc04067414c42ef18Keun-young Park        } else {
555150d8de43e71a624106e90bcc04067414c42ef18Keun-young Park            throw e;
556150d8de43e71a624106e90bcc04067414c42ef18Keun-young Park        }
557150d8de43e71a624106e90bcc04067414c42ef18Keun-young Park    }
558150d8de43e71a624106e90bcc04067414c42ef18Keun-young Park
559235f8acd3cf83079ecd0f3e1b8368b0c9886de82Vitalii Tomkiv    private CarManagerBase createCarManager(String serviceName, IBinder binder)
560235f8acd3cf83079ecd0f3e1b8368b0c9886de82Vitalii Tomkiv            throws CarNotConnectedException {
561e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park        CarManagerBase manager = null;
562e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park        switch (serviceName) {
563e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            case AUDIO_SERVICE:
564fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                manager = new CarAudioManager(binder, mContext, mEventHandler);
565e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                break;
566e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            case SENSOR_SERVICE:
5673ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup                manager = new CarSensorManager(binder, mContext, mEventHandler);
568e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                break;
569e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            case INFO_SERVICE:
570e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                manager = new CarInfoManager(binder);
571e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                break;
57246371473c416415fb6bcb8db85686669c3d65af6Vitalii Tomkiv            case APP_FOCUS_SERVICE:
5733ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup                manager = new CarAppFocusManager(binder, mEventHandler);
574e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                break;
575e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            case PACKAGE_SERVICE:
576e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                manager = new CarPackageManager(binder, mContext);
577e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                break;
578e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            case CAR_NAVIGATION_SERVICE:
5793388e7848f3a30029935463afafe9b8280939127Keun-young Park                manager = new CarNavigationStatusManager(binder);
580e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                break;
58143c04a7c87404d078db60e09d2da0061d72357c2Steve Paik            case CABIN_SERVICE:
5823ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup                manager = new CarCabinManager(binder, mContext, mEventHandler);
58343c04a7c87404d078db60e09d2da0061d72357c2Steve Paik                break;
5845c56d2a3a5bc4ef5b46a58fa56b7f4a657b0827eEnrico Granata            case DIAGNOSTIC_SERVICE:
58534010edbc8e13794307564c63b45226a8bf39e7aEnrico Granata                if (FeatureConfiguration.ENABLE_DIAGNOSTIC) {
58634010edbc8e13794307564c63b45226a8bf39e7aEnrico Granata                    manager = new CarDiagnosticManager(binder, mContext, mEventHandler);
58734010edbc8e13794307564c63b45226a8bf39e7aEnrico Granata                }
5885c56d2a3a5bc4ef5b46a58fa56b7f4a657b0827eEnrico Granata                break;
589e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            case HVAC_SERVICE:
5903ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup                manager = new CarHvacManager(binder, mContext, mEventHandler);
591e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                break;
5926e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkiv            case PROJECTION_SERVICE:
5933ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup                manager = new CarProjectionManager(binder, mEventHandler);
5946e5ee61be4c24ae4d647d687901b7c9670c25899Vitalii Tomkiv                break;
595e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            case RADIO_SERVICE:
5963ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup                manager = new CarRadioManager(binder, mEventHandler);
597e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                break;
598634e1ff49c62c32c8227ec5092743de3caca790cPavel Maltsev            case VENDOR_EXTENSION_SERVICE:
5993ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup                manager = new CarVendorExtensionManager(binder, mEventHandler);
600634e1ff49c62c32c8227ec5092743de3caca790cPavel Maltsev                break;
601e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park            case TEST_SERVICE:
602e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                /* CarTestManager exist in static library. So instead of constructing it here,
603e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                 * only pass binder wrapper so that CarTestManager can be constructed outside. */
604e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                manager = new CarTestManagerBinderWrapper(binder);
605e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park                break;
606a7d8ed1681d297bdda8345c1598c7b9a388599beAntonio Cortes            case VMS_SUBSCRIBER_SERVICE:
607c52d5f9f6190cf9a44dd6dfd3bc92386fbf023b3Antonio Cortes                if (FeatureConfiguration.ENABLE_VEHICLE_MAP_SERVICE) {
608c52d5f9f6190cf9a44dd6dfd3bc92386fbf023b3Antonio Cortes                    manager = new VmsSubscriberManager(binder, mEventHandler);
609c52d5f9f6190cf9a44dd6dfd3bc92386fbf023b3Antonio Cortes                }
610a7d8ed1681d297bdda8345c1598c7b9a388599beAntonio Cortes                break;
611e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park        }
612e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park        return manager;
613e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    }
614e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
615e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    private void startCarService() {
616e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park        Intent intent = new Intent();
617e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park        intent.setPackage(CAR_SERVICE_PACKAGE);
618e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park        intent.setAction(Car.CAR_SERVICE_INTERFACE_NAME);
61944241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park        boolean bound = mContext.bindServiceAsUser(intent, mServiceConnectionListener,
62044241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park                Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF);
62144241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park        if (!bound) {
62244241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park            mConnectionRetryCount++;
62344241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park            if (mConnectionRetryCount > CAR_SERVICE_BIND_MAX_RETRY) {
62444241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park                Log.w(CarLibLog.TAG_CAR, "cannot bind to car service after max retry");
6253ee334d8c220f631d2ea7fa225af148f41b43354Jason Tholstrup                mMainThreadEventHandler.post(mConnectionRetryFailedRunnable);
62644241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park            } else {
62744241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park                mEventHandler.postDelayed(mConnectionRetryRunnable,
62844241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park                        CAR_SERVICE_BIND_RETRY_INTERVAL_MS);
62944241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park            }
63044241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park        } else {
63144241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park            mConnectionRetryCount = 0;
63244241ffb0717f22650bbcef19c9b68c1f56cac10Keun-young Park        }
633e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park    }
634e54ac276796c6535558f8444d882adecd19ce2bdKeun-young Park
635ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private synchronized ICar getICarOrThrow() throws IllegalStateException {
636ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        if (mService == null) {
637ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            throw new IllegalStateException("not connected");
638ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        }
639ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        return mService;
640ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
641ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
642ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private void handleRemoteException(RemoteException e) {
643ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        Log.w(CarLibLog.TAG_CAR, "RemoteException", e);
644ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        disconnect();
645ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
646ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung
647ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    private void tearDownCarManagers() {
648ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        synchronized (mCarManagerLock) {
649ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            for (CarManagerBase manager: mServiceMap.values()) {
650ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung                manager.onCarDisconnected();
651ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            }
652ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung            mServiceMap.clear();
653ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung        }
654ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung    }
655ca515079e9fc0c35b1498830f67378e9ccf949e5keunyoung}
656