1a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park/*
2a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park * Copyright (C) 2016 The Android Open Source Project
3a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park *
4a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park * Licensed under the Apache License, Version 2.0 (the "License");
5a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park * you may not use this file except in compliance with the License.
6a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park * You may obtain a copy of the License at
7a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park *
8a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park *      http://www.apache.org/licenses/LICENSE-2.0
9a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park *
10a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park * Unless required by applicable law or agreed to in writing, software
11a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park * distributed under the License is distributed on an "AS IS" BASIS,
12a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park * See the License for the specific language governing permissions and
14a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park * limitations under the License.
15a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park */
16a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkpackage com.android.car.hal;
17a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
18cfe93105f637c2822da113308f113ed418d0b319Pavel Maltsevimport static android.hardware.automotive.vehicle.V2_0.VehicleProperty.HW_KEY_INPUT;
190d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev
20cfe93105f637c2822da113308f113ed418d0b319Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehicleDisplay;
21cfe93105f637c2822da113308f113ed418d0b319Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehicleHwKeyInputAction;
22cfe93105f637c2822da113308f113ed418d0b319Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
23cfe93105f637c2822da113308f113ed418d0b319Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
24338cef872d82a82c085f090472b38f568650ee66Pavel Maltsevimport android.os.SystemClock;
25a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport android.util.Log;
26338cef872d82a82c085f090472b38f568650ee66Pavel Maltsevimport android.util.SparseLongArray;
27338cef872d82a82c085f090472b38f568650ee66Pavel Maltsevimport android.view.InputDevice;
28a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport android.view.KeyEvent;
29a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
30a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport com.android.car.CarLog;
31a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
32a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport java.io.PrintWriter;
330d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsevimport java.util.Collection;
34a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport java.util.LinkedList;
35a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport java.util.List;
36a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
37a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkpublic class InputHalService extends HalServiceBase {
38a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
390d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    public static final int DISPLAY_MAIN = VehicleDisplay.MAIN;
400d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    public static final int DISPLAY_INSTRUMENT_CLUSTER = VehicleDisplay.INSTRUMENT_CLUSTER;
410d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    private final VehicleHal mHal;
42a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
43a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    public interface InputListener {
44a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        void onKeyEvent(KeyEvent event, int targetDisplay);
45a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    }
46a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
47a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    private static final boolean DBG = false;
48a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
49a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    private boolean mKeyInputSupported = false;
50a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    private InputListener mListener;
51338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev    private final SparseLongArray mKeyDownTimes = new SparseLongArray();
52a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
530d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    public InputHalService(VehicleHal hal) {
540d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        mHal = hal;
550d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    }
560d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev
57a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    public void setInputListener(InputListener listener) {
58a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        synchronized (this) {
59a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            if (!mKeyInputSupported) {
60a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park                Log.w(CarLog.TAG_INPUT, "input listener set while key input not supported");
61a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park                return;
62a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            }
63a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            mListener = listener;
64a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        }
6579d5e12ad8708c1f7f7f1a60aaeb349ac7ed0f7bPavel Maltsev        mHal.subscribeProperty(this, HW_KEY_INPUT);
66a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    }
67a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
68a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    public synchronized boolean isKeyInputSupported() {
69a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        return mKeyInputSupported;
70a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    }
71a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
72a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    @Override
73a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    public void init() {
74a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    }
75a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
76a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    @Override
77a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    public void release() {
78a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        synchronized (this) {
79a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            mListener = null;
80a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            mKeyInputSupported = false;
81a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        }
82a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    }
83a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
84a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    @Override
850d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev    public Collection<VehiclePropConfig> takeSupportedProperties(
860d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            Collection<VehiclePropConfig> allProperties) {
870d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        List<VehiclePropConfig> supported = new LinkedList<>();
88a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        for (VehiclePropConfig p: allProperties) {
890d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            if (p.prop == HW_KEY_INPUT) {
90a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park                supported.add(p);
91a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park                synchronized (this) {
92a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park                    mKeyInputSupported = true;
93a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park                }
94a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            }
95a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        }
96a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        return supported;
97a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    }
98a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
99a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    @Override
100a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    public void handleHalEvents(List<VehiclePropValue> values) {
1010d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev        InputListener listener;
102a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        synchronized (this) {
103a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            listener = mListener;
104a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        }
105a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        if (listener == null) {
106a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            Log.w(CarLog.TAG_INPUT, "Input event while listener is null");
107a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            return;
108a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        }
109a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        for (VehiclePropValue v : values) {
1100d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            if (v.prop != HW_KEY_INPUT) {
111a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park                Log.e(CarLog.TAG_INPUT, "Wrong event dispatched, prop:0x" +
1120d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev                        Integer.toHexString(v.prop));
113a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park                continue;
114a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            }
1150d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            int action = (v.value.int32Values.get(0) == VehicleHwKeyInputAction.ACTION_DOWN) ?
116a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park                            KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
1170d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            int code = v.value.int32Values.get(1);
1180d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev            int display = v.value.int32Values.get(2);
119a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            if (DBG) {
1200d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev                Log.i(CarLog.TAG_INPUT, "hal event code:" + code + ", action:" + action +
1210d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev                        ", display:" + display);
122a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park            }
123338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev
124338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev            dispatchKeyEvent(listener, action, code, display);
125338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev        }
126338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev    }
127338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev
128338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev    private void dispatchKeyEvent(InputListener listener, int action, int code, int display) {
129338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev        long eventTime = SystemClock.uptimeMillis();
130338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev
131338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev        if (action == KeyEvent.ACTION_DOWN) {
132338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev            mKeyDownTimes.put(code, eventTime);
133a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        }
134338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev
135338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev        long downTime = action == KeyEvent.ACTION_UP
136338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                ? mKeyDownTimes.get(code, eventTime) : eventTime;
137338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev
138338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev        KeyEvent event = KeyEvent.obtain(
139338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                downTime,
140338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                eventTime,
141338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                action,
142338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                code,
143338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                0 /* repeat */,
144338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                0 /* meta state */,
145338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                0 /* deviceId*/,
146338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                0 /* scancode */,
147338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                0 /* flags */,
148338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                InputDevice.SOURCE_CLASS_BUTTON,
149338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev                null /* characters */);
150338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev
151338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev        listener.onKeyEvent(event, display);
152338cef872d82a82c085f090472b38f568650ee66Pavel Maltsev        event.recycle();
153a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    }
154a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
155a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    @Override
156a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    public void dump(PrintWriter writer) {
157a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        writer.println("*Input HAL*");
158a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park        writer.println("mKeyInputSupported:" + mKeyInputSupported);
159a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park    }
160a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park
161a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park}
162