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.hal; 17 18 import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.HW_KEY_INPUT; 19 20 import android.hardware.automotive.vehicle.V2_0.VehicleDisplay; 21 import android.hardware.automotive.vehicle.V2_0.VehicleHwKeyInputAction; 22 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; 23 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 24 import android.os.SystemClock; 25 import android.util.Log; 26 import android.util.SparseLongArray; 27 import android.view.InputDevice; 28 import android.view.KeyEvent; 29 30 import com.android.car.CarLog; 31 32 import java.io.PrintWriter; 33 import java.util.Collection; 34 import java.util.LinkedList; 35 import java.util.List; 36 37 public class InputHalService extends HalServiceBase { 38 39 public static final int DISPLAY_MAIN = VehicleDisplay.MAIN; 40 public static final int DISPLAY_INSTRUMENT_CLUSTER = VehicleDisplay.INSTRUMENT_CLUSTER; 41 private final VehicleHal mHal; 42 43 public interface InputListener { onKeyEvent(KeyEvent event, int targetDisplay)44 void onKeyEvent(KeyEvent event, int targetDisplay); 45 } 46 47 private static final boolean DBG = false; 48 49 private boolean mKeyInputSupported = false; 50 private InputListener mListener; 51 private final SparseLongArray mKeyDownTimes = new SparseLongArray(); 52 InputHalService(VehicleHal hal)53 public InputHalService(VehicleHal hal) { 54 mHal = hal; 55 } 56 setInputListener(InputListener listener)57 public void setInputListener(InputListener listener) { 58 synchronized (this) { 59 if (!mKeyInputSupported) { 60 Log.w(CarLog.TAG_INPUT, "input listener set while key input not supported"); 61 return; 62 } 63 mListener = listener; 64 } 65 mHal.subscribeProperty(this, HW_KEY_INPUT); 66 } 67 isKeyInputSupported()68 public synchronized boolean isKeyInputSupported() { 69 return mKeyInputSupported; 70 } 71 72 @Override init()73 public void init() { 74 } 75 76 @Override release()77 public void release() { 78 synchronized (this) { 79 mListener = null; 80 mKeyInputSupported = false; 81 } 82 } 83 84 @Override takeSupportedProperties( Collection<VehiclePropConfig> allProperties)85 public Collection<VehiclePropConfig> takeSupportedProperties( 86 Collection<VehiclePropConfig> allProperties) { 87 List<VehiclePropConfig> supported = new LinkedList<>(); 88 for (VehiclePropConfig p: allProperties) { 89 if (p.prop == HW_KEY_INPUT) { 90 supported.add(p); 91 synchronized (this) { 92 mKeyInputSupported = true; 93 } 94 } 95 } 96 return supported; 97 } 98 99 @Override handleHalEvents(List<VehiclePropValue> values)100 public void handleHalEvents(List<VehiclePropValue> values) { 101 InputListener listener; 102 synchronized (this) { 103 listener = mListener; 104 } 105 if (listener == null) { 106 Log.w(CarLog.TAG_INPUT, "Input event while listener is null"); 107 return; 108 } 109 for (VehiclePropValue v : values) { 110 if (v.prop != HW_KEY_INPUT) { 111 Log.e(CarLog.TAG_INPUT, "Wrong event dispatched, prop:0x" + 112 Integer.toHexString(v.prop)); 113 continue; 114 } 115 int action = (v.value.int32Values.get(0) == VehicleHwKeyInputAction.ACTION_DOWN) ? 116 KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP; 117 int code = v.value.int32Values.get(1); 118 int display = v.value.int32Values.get(2); 119 if (DBG) { 120 Log.i(CarLog.TAG_INPUT, "hal event code:" + code + ", action:" + action + 121 ", display:" + display); 122 } 123 124 dispatchKeyEvent(listener, action, code, display); 125 } 126 } 127 dispatchKeyEvent(InputListener listener, int action, int code, int display)128 private void dispatchKeyEvent(InputListener listener, int action, int code, int display) { 129 long eventTime = SystemClock.uptimeMillis(); 130 131 if (action == KeyEvent.ACTION_DOWN) { 132 mKeyDownTimes.put(code, eventTime); 133 } 134 135 long downTime = action == KeyEvent.ACTION_UP 136 ? mKeyDownTimes.get(code, eventTime) : eventTime; 137 138 KeyEvent event = KeyEvent.obtain( 139 downTime, 140 eventTime, 141 action, 142 code, 143 0 /* repeat */, 144 0 /* meta state */, 145 0 /* deviceId*/, 146 0 /* scancode */, 147 0 /* flags */, 148 InputDevice.SOURCE_CLASS_BUTTON, 149 null /* characters */); 150 151 listener.onKeyEvent(event, display); 152 event.recycle(); 153 } 154 155 @Override dump(PrintWriter writer)156 public void dump(PrintWriter writer) { 157 writer.println("*Input HAL*"); 158 writer.println("mKeyInputSupported:" + mKeyInputSupported); 159 } 160 161 } 162