Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | package com.android.car; |
| 17 | |
Pavel Maltsev | 338cef8 | 2016-07-26 16:04:15 -0700 | [diff] [blame] | 18 | import static android.hardware.input.InputManager.INJECT_INPUT_EVENT_MODE_ASYNC; |
| 19 | |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 20 | import android.car.input.CarInputHandlingService; |
| 21 | import android.car.input.CarInputHandlingService.InputFilter; |
| 22 | import android.car.input.ICarInputListener; |
| 23 | import android.content.ComponentName; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 24 | import android.content.Context; |
| 25 | import android.content.Intent; |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 26 | import android.content.ServiceConnection; |
Pavel Maltsev | 338cef8 | 2016-07-26 16:04:15 -0700 | [diff] [blame] | 27 | import android.hardware.input.InputManager; |
Vitalii Tomkiv | e2142e5 | 2016-04-29 11:35:26 -0700 | [diff] [blame] | 28 | import android.net.Uri; |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 29 | import android.os.Binder; |
| 30 | import android.os.Bundle; |
| 31 | import android.os.IBinder; |
| 32 | import android.os.Parcel; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 33 | import android.os.ParcelFileDescriptor; |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 34 | import android.os.RemoteException; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 35 | import android.os.SystemClock; |
| 36 | import android.os.UserHandle; |
Vitalii Tomkiv | e2142e5 | 2016-04-29 11:35:26 -0700 | [diff] [blame] | 37 | import android.provider.CallLog.Calls; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 38 | import android.speech.RecognizerIntent; |
Vitalii Tomkiv | e2142e5 | 2016-04-29 11:35:26 -0700 | [diff] [blame] | 39 | import android.telecom.TelecomManager; |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 40 | import android.text.TextUtils; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 41 | import android.util.Log; |
| 42 | import android.view.KeyEvent; |
| 43 | |
| 44 | import com.android.car.hal.InputHalService; |
| 45 | import com.android.car.hal.VehicleHal; |
| 46 | |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 47 | import java.io.PrintWriter; |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 48 | import java.util.HashMap; |
| 49 | import java.util.HashSet; |
| 50 | import java.util.Map; |
| 51 | import java.util.Set; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 52 | |
| 53 | public class CarInputService implements CarServiceBase, InputHalService.InputListener { |
| 54 | |
| 55 | public interface KeyEventListener { |
Yao Chen | c4d442f | 2016-04-08 11:33:47 -0700 | [diff] [blame] | 56 | boolean onKeyEvent(KeyEvent event); |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 57 | } |
| 58 | |
Vitalii Tomkiv | e2142e5 | 2016-04-29 11:35:26 -0700 | [diff] [blame] | 59 | private static final long LONG_PRESS_TIME_MS = 1000; |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 60 | private static final boolean DBG = false; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 61 | |
| 62 | private final Context mContext; |
Vitalii Tomkiv | e2142e5 | 2016-04-29 11:35:26 -0700 | [diff] [blame] | 63 | private final TelecomManager mTelecomManager; |
Pavel Maltsev | 338cef8 | 2016-07-26 16:04:15 -0700 | [diff] [blame] | 64 | private final InputManager mInputManager; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 65 | |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 66 | private KeyEventListener mVoiceAssistantKeyListener; |
| 67 | private KeyEventListener mLongVoiceAssistantKeyListener; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 68 | private long mLastVoiceKeyDownTime = 0; |
| 69 | |
Vitalii Tomkiv | e2142e5 | 2016-04-29 11:35:26 -0700 | [diff] [blame] | 70 | private long mLastCallKeyDownTime = 0; |
| 71 | |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 72 | private KeyEventListener mInstrumentClusterKeyListener; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 73 | |
Keun-young Park | 07182c7 | 2016-03-18 18:01:29 -0700 | [diff] [blame] | 74 | private KeyEventListener mVolumeKeyListener; |
| 75 | |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 76 | private ICarInputListener mCarInputListener; |
| 77 | private boolean mCarInputListenerBound = false; |
| 78 | private final Map<Integer, Set<Integer>> mHandledKeys = new HashMap<>(); |
| 79 | |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 80 | private int mKeyEventCount = 0; |
| 81 | |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 82 | private final Binder mCallback = new Binder() { |
| 83 | @Override |
| 84 | protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) { |
| 85 | if (code == CarInputHandlingService.INPUT_CALLBACK_BINDER_CODE) { |
| 86 | data.setDataPosition(0); |
| 87 | InputFilter[] handledKeys = (InputFilter[]) data.createTypedArray( |
| 88 | InputFilter.CREATOR); |
| 89 | if (handledKeys != null) { |
| 90 | setHandledKeys(handledKeys); |
| 91 | } |
| 92 | return true; |
| 93 | } |
| 94 | return false; |
| 95 | } |
| 96 | }; |
| 97 | |
| 98 | private final ServiceConnection mInputServiceConnection = new ServiceConnection() { |
| 99 | @Override |
| 100 | public void onServiceConnected(ComponentName name, IBinder binder) { |
| 101 | if (DBG) { |
| 102 | Log.d(CarLog.TAG_INPUT, "onServiceConnected, name: " |
| 103 | + name + ", binder: " + binder); |
| 104 | } |
| 105 | mCarInputListener = ICarInputListener.Stub.asInterface(binder); |
| 106 | |
| 107 | try { |
| 108 | binder.linkToDeath(() -> CarServiceUtils.runOnMainSync(() -> { |
| 109 | Log.w(CarLog.TAG_INPUT, "Input service died. Trying to rebind..."); |
| 110 | mCarInputListener = null; |
| 111 | // Try to rebind with input service. |
| 112 | mCarInputListenerBound = bindCarInputService(); |
| 113 | }), 0); |
| 114 | } catch (RemoteException e) { |
| 115 | Log.e(CarLog.TAG_INPUT, e.getMessage(), e); |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | @Override |
| 120 | public void onServiceDisconnected(ComponentName name) { |
| 121 | Log.d(CarLog.TAG_INPUT, "onServiceDisconnected, name: " + name); |
| 122 | mCarInputListener = null; |
| 123 | // Try to rebind with input service. |
| 124 | mCarInputListenerBound = bindCarInputService(); |
| 125 | } |
| 126 | }; |
| 127 | |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 128 | public CarInputService(Context context) { |
| 129 | mContext = context; |
Pavel Maltsev | 338cef8 | 2016-07-26 16:04:15 -0700 | [diff] [blame] | 130 | mTelecomManager = context.getSystemService(TelecomManager.class); |
| 131 | mInputManager = context.getSystemService(InputManager.class); |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 132 | } |
| 133 | |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 134 | private synchronized void setHandledKeys(InputFilter[] handledKeys) { |
| 135 | mHandledKeys.clear(); |
| 136 | for (InputFilter handledKey : handledKeys) { |
| 137 | Set<Integer> displaySet = mHandledKeys.get(handledKey.mTargetDisplay); |
| 138 | if (displaySet == null) { |
| 139 | displaySet = new HashSet<Integer>(); |
| 140 | mHandledKeys.put(handledKey.mTargetDisplay, displaySet); |
| 141 | } |
| 142 | displaySet.add(handledKey.mKeyCode); |
| 143 | } |
| 144 | } |
| 145 | |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 146 | /** |
Vitalii Tomkiv | 61e2c23 | 2016-03-08 10:48:51 -0800 | [diff] [blame] | 147 | * Set listener for listening voice assistant key event. Setting to null stops listening. |
| 148 | * If listener is not set, default behavior will be done for short press. |
| 149 | * If listener is set, short key press will lead into calling the listener. |
| 150 | * @param listener |
| 151 | */ |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 152 | public void setVoiceAssistantKeyListener(KeyEventListener listener) { |
Vitalii Tomkiv | 61e2c23 | 2016-03-08 10:48:51 -0800 | [diff] [blame] | 153 | synchronized (this) { |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 154 | mVoiceAssistantKeyListener = listener; |
Vitalii Tomkiv | 61e2c23 | 2016-03-08 10:48:51 -0800 | [diff] [blame] | 155 | } |
| 156 | } |
| 157 | |
| 158 | /** |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 159 | * Set listener for listening long voice assistant key event. Setting to null stops listening. |
Vitalii Tomkiv | 61e2c23 | 2016-03-08 10:48:51 -0800 | [diff] [blame] | 160 | * If listener is not set, default behavior will be done for long press. |
| 161 | * If listener is set, short long press will lead into calling the listener. |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 162 | * @param listener |
| 163 | */ |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 164 | public void setLongVoiceAssistantKeyListener(KeyEventListener listener) { |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 165 | synchronized (this) { |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 166 | mLongVoiceAssistantKeyListener = listener; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 167 | } |
| 168 | } |
| 169 | |
| 170 | public void setInstrumentClusterKeyListener(KeyEventListener listener) { |
| 171 | synchronized (this) { |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 172 | mInstrumentClusterKeyListener = listener; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 173 | } |
| 174 | } |
| 175 | |
Keun-young Park | 07182c7 | 2016-03-18 18:01:29 -0700 | [diff] [blame] | 176 | public void setVolumeKeyListener(KeyEventListener listener) { |
| 177 | synchronized (this) { |
| 178 | mVolumeKeyListener = listener; |
| 179 | } |
| 180 | } |
| 181 | |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 182 | @Override |
| 183 | public void init() { |
| 184 | InputHalService hal = VehicleHal.getInstance().getInputHal(); |
| 185 | if (!hal.isKeyInputSupported()) { |
| 186 | Log.w(CarLog.TAG_INPUT, "Hal does not support key input."); |
| 187 | return; |
| 188 | } |
Pavel Maltsev | 338cef8 | 2016-07-26 16:04:15 -0700 | [diff] [blame] | 189 | |
| 190 | |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 191 | hal.setInputListener(this); |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 192 | mCarInputListenerBound = bindCarInputService(); |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | @Override |
| 196 | public void release() { |
| 197 | synchronized (this) { |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 198 | mVoiceAssistantKeyListener = null; |
| 199 | mLongVoiceAssistantKeyListener = null; |
| 200 | mInstrumentClusterKeyListener = null; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 201 | mKeyEventCount = 0; |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 202 | if (mCarInputListenerBound) { |
| 203 | mContext.unbindService(mInputServiceConnection); |
| 204 | mCarInputListenerBound = false; |
| 205 | } |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 206 | } |
| 207 | } |
| 208 | |
| 209 | @Override |
| 210 | public void onKeyEvent(KeyEvent event, int targetDisplay) { |
| 211 | synchronized (this) { |
| 212 | mKeyEventCount++; |
| 213 | } |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 214 | if (handleSystemEvent(event)) { |
| 215 | // System event handled, nothing more to do here. |
| 216 | return; |
| 217 | } |
| 218 | if (mCarInputListener != null && isCustomEventHandler(event, targetDisplay)) { |
| 219 | try { |
| 220 | mCarInputListener.onKeyEvent(event, targetDisplay); |
| 221 | } catch (RemoteException e) { |
| 222 | Log.e(CarLog.TAG_INPUT, "Error while calling car input service", e); |
| 223 | } |
| 224 | // Custom input service handled the event, nothing more to do here. |
| 225 | return; |
| 226 | } |
| 227 | |
| 228 | switch (event.getKeyCode()) { |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 229 | case KeyEvent.KEYCODE_VOICE_ASSIST: |
| 230 | handleVoiceAssistKey(event); |
| 231 | return; |
Vitalii Tomkiv | e2142e5 | 2016-04-29 11:35:26 -0700 | [diff] [blame] | 232 | case KeyEvent.KEYCODE_CALL: |
| 233 | handleCallKey(event); |
| 234 | return; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 235 | default: |
| 236 | break; |
| 237 | } |
| 238 | if (targetDisplay == InputHalService.DISPLAY_INSTRUMENT_CLUSTER) { |
| 239 | handleInstrumentClusterKey(event); |
| 240 | } else { |
| 241 | handleMainDisplayKey(event); |
| 242 | } |
| 243 | } |
| 244 | |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 245 | private synchronized boolean isCustomEventHandler(KeyEvent event, int targetDisplay) { |
| 246 | Set<Integer> displaySet = mHandledKeys.get(targetDisplay); |
| 247 | if (displaySet == null) { |
| 248 | return false; |
| 249 | } |
| 250 | return displaySet.contains(event.getKeyCode()); |
| 251 | } |
| 252 | |
| 253 | private boolean handleSystemEvent(KeyEvent event) { |
| 254 | switch (event.getKeyCode()) { |
| 255 | case KeyEvent.KEYCODE_VOLUME_UP: |
| 256 | case KeyEvent.KEYCODE_VOLUME_DOWN: |
| 257 | handleVolumeKey(event); |
| 258 | return true; |
| 259 | default: |
| 260 | return false; |
| 261 | } |
| 262 | } |
| 263 | |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 264 | private void handleVoiceAssistKey(KeyEvent event) { |
| 265 | int action = event.getAction(); |
| 266 | if (action == KeyEvent.ACTION_DOWN) { |
| 267 | long now = SystemClock.elapsedRealtime(); |
| 268 | synchronized (this) { |
| 269 | mLastVoiceKeyDownTime = now; |
| 270 | } |
| 271 | } else if (action == KeyEvent.ACTION_UP) { |
| 272 | // if no listener, do not handle long press |
| 273 | KeyEventListener listener = null; |
Vitalii Tomkiv | 61e2c23 | 2016-03-08 10:48:51 -0800 | [diff] [blame] | 274 | KeyEventListener shortPressListener = null; |
| 275 | KeyEventListener longPressListener = null; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 276 | long downTime; |
| 277 | synchronized (this) { |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 278 | shortPressListener = mVoiceAssistantKeyListener; |
| 279 | longPressListener = mLongVoiceAssistantKeyListener; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 280 | downTime = mLastVoiceKeyDownTime; |
| 281 | } |
Vitalii Tomkiv | 61e2c23 | 2016-03-08 10:48:51 -0800 | [diff] [blame] | 282 | if (shortPressListener == null && longPressListener == null) { |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 283 | launchDefaultVoiceAssistantHandler(); |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 284 | } else { |
| 285 | long duration = SystemClock.elapsedRealtime() - downTime; |
Vitalii Tomkiv | e2142e5 | 2016-04-29 11:35:26 -0700 | [diff] [blame] | 286 | listener = (duration > LONG_PRESS_TIME_MS |
Vitalii Tomkiv | 61e2c23 | 2016-03-08 10:48:51 -0800 | [diff] [blame] | 287 | ? longPressListener : shortPressListener); |
| 288 | if (listener != null) { |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 289 | listener.onKeyEvent(event); |
| 290 | } else { |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 291 | launchDefaultVoiceAssistantHandler(); |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 292 | } |
| 293 | } |
| 294 | } |
| 295 | } |
| 296 | |
Vitalii Tomkiv | e2142e5 | 2016-04-29 11:35:26 -0700 | [diff] [blame] | 297 | private void handleCallKey(KeyEvent event) { |
| 298 | int action = event.getAction(); |
| 299 | if (action == KeyEvent.ACTION_DOWN) { |
| 300 | // Only handle if it's ringing when button down. |
| 301 | if (mTelecomManager != null && mTelecomManager.isRinging()) { |
| 302 | Log.i(CarLog.TAG_INPUT, "call key while rinning. Answer the call!"); |
| 303 | mTelecomManager.acceptRingingCall(); |
| 304 | return; |
| 305 | } |
| 306 | |
| 307 | long now = SystemClock.elapsedRealtime(); |
| 308 | synchronized (this) { |
| 309 | mLastCallKeyDownTime = now; |
| 310 | } |
| 311 | } else if (action == KeyEvent.ACTION_UP) { |
| 312 | long downTime; |
| 313 | synchronized (this) { |
| 314 | downTime = mLastCallKeyDownTime; |
| 315 | } |
| 316 | long duration = SystemClock.elapsedRealtime() - downTime; |
| 317 | if (duration > LONG_PRESS_TIME_MS) { |
| 318 | dialLastCallHandler(); |
| 319 | } else { |
| 320 | launchDialerHandler(); |
| 321 | } |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | private void launchDialerHandler() { |
| 326 | Log.i(CarLog.TAG_INPUT, "call key, launch dialer intent"); |
| 327 | Intent dialerIntent = new Intent(Intent.ACTION_DIAL); |
| 328 | mContext.startActivityAsUser(dialerIntent, null, UserHandle.CURRENT_OR_SELF); |
| 329 | } |
| 330 | |
| 331 | private void dialLastCallHandler() { |
| 332 | Log.i(CarLog.TAG_INPUT, "call key, dialing last call"); |
| 333 | |
| 334 | String lastNumber = Calls.getLastOutgoingCall(mContext); |
Vitalii Tomkiv | e2142e5 | 2016-04-29 11:35:26 -0700 | [diff] [blame] | 335 | if (lastNumber != null && !lastNumber.isEmpty()) { |
| 336 | Intent callLastNumberIntent = new Intent(Intent.ACTION_CALL) |
| 337 | .setData(Uri.fromParts("tel", lastNumber, null)) |
| 338 | .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| 339 | mContext.startActivityAsUser(callLastNumberIntent, null, UserHandle.CURRENT_OR_SELF); |
| 340 | } |
| 341 | } |
| 342 | |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 343 | private void launchDefaultVoiceAssistantHandler() { |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 344 | Log.i(CarLog.TAG_INPUT, "voice key, launch default intent"); |
| 345 | Intent voiceIntent = |
| 346 | new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); |
| 347 | mContext.startActivityAsUser(voiceIntent, null, UserHandle.CURRENT_OR_SELF); |
| 348 | } |
| 349 | |
| 350 | private void handleInstrumentClusterKey(KeyEvent event) { |
| 351 | KeyEventListener listener = null; |
| 352 | synchronized (this) { |
Pavel Maltsev | e11ad3a | 2016-03-25 15:40:24 -0700 | [diff] [blame] | 353 | listener = mInstrumentClusterKeyListener; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 354 | } |
| 355 | if (listener == null) { |
| 356 | return; |
| 357 | } |
| 358 | listener.onKeyEvent(event); |
| 359 | } |
| 360 | |
Keun-young Park | 07182c7 | 2016-03-18 18:01:29 -0700 | [diff] [blame] | 361 | private void handleVolumeKey(KeyEvent event) { |
Yao Chen | c4d442f | 2016-04-08 11:33:47 -0700 | [diff] [blame] | 362 | KeyEventListener listener; |
Keun-young Park | 07182c7 | 2016-03-18 18:01:29 -0700 | [diff] [blame] | 363 | synchronized (this) { |
| 364 | listener = mVolumeKeyListener; |
| 365 | } |
Yao Chen | c4d442f | 2016-04-08 11:33:47 -0700 | [diff] [blame] | 366 | if (listener != null) { |
| 367 | listener.onKeyEvent(event); |
Keun-young Park | 07182c7 | 2016-03-18 18:01:29 -0700 | [diff] [blame] | 368 | } |
Keun-young Park | 07182c7 | 2016-03-18 18:01:29 -0700 | [diff] [blame] | 369 | } |
| 370 | |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 371 | private void handleMainDisplayKey(KeyEvent event) { |
Pavel Maltsev | 338cef8 | 2016-07-26 16:04:15 -0700 | [diff] [blame] | 372 | mInputManager.injectInputEvent(event, INJECT_INPUT_EVENT_MODE_ASYNC); |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 373 | } |
| 374 | |
| 375 | @Override |
| 376 | public void dump(PrintWriter writer) { |
| 377 | writer.println("*Input Service*"); |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 378 | writer.println("mCarInputListenerBound:" + mCarInputListenerBound); |
| 379 | writer.println("mCarInputListener:" + mCarInputListener); |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 380 | writer.println("mLastVoiceKeyDownTime:" + mLastVoiceKeyDownTime + |
| 381 | ",mKeyEventCount:" + mKeyEventCount); |
| 382 | } |
| 383 | |
Vitalii Tomkiv | 2bd0692 | 2016-07-26 11:07:48 -0700 | [diff] [blame] | 384 | private boolean bindCarInputService() { |
| 385 | String carInputService = mContext.getString(R.string.inputService); |
| 386 | if (TextUtils.isEmpty(carInputService)) { |
| 387 | Log.i(CarLog.TAG_INPUT, "Custom input service was not configured"); |
| 388 | return false; |
| 389 | } |
| 390 | |
| 391 | Log.d(CarLog.TAG_INPUT, "bindCarInputService, component: " + carInputService); |
| 392 | |
| 393 | Intent intent = new Intent(); |
| 394 | Bundle extras = new Bundle(); |
| 395 | extras.putBinder(CarInputHandlingService.INPUT_CALLBACK_BINDER_KEY, mCallback); |
| 396 | intent.putExtras(extras); |
| 397 | intent.setComponent(ComponentName.unflattenFromString(carInputService)); |
| 398 | // Explicitly start service as we do not use BIND_AUTO_CREATE flag to handle service crash. |
| 399 | mContext.startService(intent); |
| 400 | return mContext.bindService(intent, mInputServiceConnection, Context.BIND_IMPORTANT); |
| 401 | } |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 402 | } |