| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.car.hal; |
| |
| import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.HW_KEY_INPUT; |
| |
| import android.hardware.automotive.vehicle.V2_0.VehicleDisplay; |
| import android.hardware.automotive.vehicle.V2_0.VehicleHwKeyInputAction; |
| import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; |
| import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; |
| import android.os.SystemClock; |
| import android.util.Log; |
| import android.util.SparseLongArray; |
| import android.view.InputDevice; |
| import android.view.KeyEvent; |
| |
| import com.android.car.CarLog; |
| |
| import java.io.PrintWriter; |
| import java.util.Collection; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| public class InputHalService extends HalServiceBase { |
| |
| public static final int DISPLAY_MAIN = VehicleDisplay.MAIN; |
| public static final int DISPLAY_INSTRUMENT_CLUSTER = VehicleDisplay.INSTRUMENT_CLUSTER; |
| private final VehicleHal mHal; |
| |
| public interface InputListener { |
| void onKeyEvent(KeyEvent event, int targetDisplay); |
| } |
| |
| private static final boolean DBG = false; |
| |
| private boolean mKeyInputSupported = false; |
| private InputListener mListener; |
| private final SparseLongArray mKeyDownTimes = new SparseLongArray(); |
| |
| public InputHalService(VehicleHal hal) { |
| mHal = hal; |
| } |
| |
| public void setInputListener(InputListener listener) { |
| synchronized (this) { |
| if (!mKeyInputSupported) { |
| Log.w(CarLog.TAG_INPUT, "input listener set while key input not supported"); |
| return; |
| } |
| mListener = listener; |
| } |
| mHal.subscribeProperty(this, HW_KEY_INPUT); |
| } |
| |
| public synchronized boolean isKeyInputSupported() { |
| return mKeyInputSupported; |
| } |
| |
| @Override |
| public void init() { |
| } |
| |
| @Override |
| public void release() { |
| synchronized (this) { |
| mListener = null; |
| mKeyInputSupported = false; |
| } |
| } |
| |
| @Override |
| public Collection<VehiclePropConfig> takeSupportedProperties( |
| Collection<VehiclePropConfig> allProperties) { |
| List<VehiclePropConfig> supported = new LinkedList<>(); |
| for (VehiclePropConfig p: allProperties) { |
| if (p.prop == HW_KEY_INPUT) { |
| supported.add(p); |
| synchronized (this) { |
| mKeyInputSupported = true; |
| } |
| } |
| } |
| return supported; |
| } |
| |
| @Override |
| public void handleHalEvents(List<VehiclePropValue> values) { |
| InputListener listener; |
| synchronized (this) { |
| listener = mListener; |
| } |
| if (listener == null) { |
| Log.w(CarLog.TAG_INPUT, "Input event while listener is null"); |
| return; |
| } |
| for (VehiclePropValue v : values) { |
| if (v.prop != HW_KEY_INPUT) { |
| Log.e(CarLog.TAG_INPUT, "Wrong event dispatched, prop:0x" + |
| Integer.toHexString(v.prop)); |
| continue; |
| } |
| int action = (v.value.int32Values.get(0) == VehicleHwKeyInputAction.ACTION_DOWN) ? |
| KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP; |
| int code = v.value.int32Values.get(1); |
| int display = v.value.int32Values.get(2); |
| if (DBG) { |
| Log.i(CarLog.TAG_INPUT, "hal event code:" + code + ", action:" + action + |
| ", display:" + display); |
| } |
| |
| dispatchKeyEvent(listener, action, code, display); |
| } |
| } |
| |
| private void dispatchKeyEvent(InputListener listener, int action, int code, int display) { |
| long eventTime = SystemClock.uptimeMillis(); |
| |
| if (action == KeyEvent.ACTION_DOWN) { |
| mKeyDownTimes.put(code, eventTime); |
| } |
| |
| long downTime = action == KeyEvent.ACTION_UP |
| ? mKeyDownTimes.get(code, eventTime) : eventTime; |
| |
| KeyEvent event = KeyEvent.obtain( |
| downTime, |
| eventTime, |
| action, |
| code, |
| 0 /* repeat */, |
| 0 /* meta state */, |
| 0 /* deviceId*/, |
| 0 /* scancode */, |
| 0 /* flags */, |
| InputDevice.SOURCE_CLASS_BUTTON, |
| null /* characters */); |
| |
| listener.onKeyEvent(event, display); |
| event.recycle(); |
| } |
| |
| @Override |
| public void dump(PrintWriter writer) { |
| writer.println("*Input HAL*"); |
| writer.println("mKeyInputSupported:" + mKeyInputSupported); |
| } |
| |
| } |