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.google.android.car.kitchensink.input; 17a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park 189bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granataimport static android.hardware.automotive.vehicle.V2_0.SubscribeFlags.EVENTS_FROM_ANDROID; 199bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granataimport static android.hardware.automotive.vehicle.V2_0.SubscribeFlags.EVENTS_FROM_CAR; 2031966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport static android.hardware.automotive.vehicle.V2_0.VehicleDisplay.INSTRUMENT_CLUSTER; 219bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granataimport static android.hardware.automotive.vehicle.V2_0.VehicleHwKeyInputAction.ACTION_DOWN; 229bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granataimport static android.hardware.automotive.vehicle.V2_0.VehicleProperty.HW_KEY_INPUT; 2331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev 24a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport android.annotation.Nullable; 25e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsevimport android.annotation.StringRes; 2631966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.IVehicle; 279bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granataimport android.hardware.automotive.vehicle.V2_0.IVehicleCallback; 289bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granataimport android.hardware.automotive.vehicle.V2_0.IVehicleCallback.Stub; 299bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granataimport android.hardware.automotive.vehicle.V2_0.SubscribeOptions; 3031966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehicleArea; 3131966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehicleDisplay; 3231966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 3331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehicleProperty; 3431966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup; 3531966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehiclePropertyStatus; 3631966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehiclePropertyType; 37a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport android.os.Bundle; 3831966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport android.os.RemoteException; 39fa3290a37081cfa6d4862d206f6b62293957adedRodrigo Lagosimport android.support.v4.app.Fragment; 403ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granataimport android.text.method.ScrollingMovementMethod; 41a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport android.util.Log; 42a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport android.view.KeyEvent; 43a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport android.view.LayoutInflater; 44a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport android.view.View; 45a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport android.view.ViewGroup; 46a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkimport android.widget.Button; 47e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsevimport android.widget.LinearLayout; 4831966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport android.widget.TextView; 4931966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport android.widget.Toast; 50e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev 513ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granataimport com.android.car.keventreader.EventReaderService; 523ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granataimport com.android.car.keventreader.IEventCallback; 533ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granataimport com.android.car.keventreader.KeypressEvent; 543ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata 55e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsevimport com.google.android.car.kitchensink.R; 5631966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport com.google.android.collect.Lists; 57e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev 58e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsevimport java.util.ArrayList; 59e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsevimport java.util.Collections; 60e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsevimport java.util.List; 6131966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsevimport java.util.NoSuchElementException; 62a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park 63a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park/** 64a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park * Test input event handling to system. 65a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park * vehicle hal should have VEHICLE_PROPERTY_HW_KEY_INPUT support for this to work. 66a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park */ 67a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Parkpublic class InputTestFragment extends Fragment { 68a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park 69a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park private static final String TAG = "CAR.INPUT.KS"; 70a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park 71e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev private static final Button BREAK_LINE = null; 72e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev 73e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev private final List<View> mButtons = new ArrayList<>(); 74a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park 75c7f46a9104419e071302adcb2a5908177b9fd41cChao Yan // This is fake data generation property available only in emulated VHAL implementation. 7631966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev private static final int sGenerateFakeDataControllingProperty = 7731966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev 0x0666 | VehiclePropertyGroup.VENDOR | VehicleArea.GLOBAL | VehiclePropertyType.MIXED; 78c7f46a9104419e071302adcb2a5908177b9fd41cChao Yan // The key press command is sent with the fake data generation property. It's matching the 79c7f46a9104419e071302adcb2a5908177b9fd41cChao Yan // command defined in the emulated VHAL implementation. 80c7f46a9104419e071302adcb2a5908177b9fd41cChao Yan private static final int sKeyPressCommand = 100; 8131966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev 8231966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev private IVehicle mVehicle; 8331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev 843ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata private EventReaderService mEventReaderService; 853ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata 863ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata private final IEventCallback.Stub mKeypressEventHandler = new IEventCallback.Stub() { 873ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata private String prettyPrint(KeypressEvent event) { 883ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata return String.format("Event{source = %s, keycode = %s, key%s}\n", 893ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata event.source, 903ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata event.keycodeToString(), 913ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata event.isKeydown ? "down" : "up"); 923ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata } 933ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata 943ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata @Override 953ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata public void onEvent(KeypressEvent keypressEvent) throws RemoteException { 963ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata Log.d(TAG, "received event " + keypressEvent); 979bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata synchronized (mInputEventsList) { 989bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata mInputEventsList.append(prettyPrint(keypressEvent)); 999bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata } 1003ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata } 1013ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata }; 1023ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata 1039bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata private final IVehicleCallback.Stub mHalKeyEventHandler = new Stub() { 1049bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata private String prettyPrint(VehiclePropValue event) { 1059bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata if (event.prop != HW_KEY_INPUT) return ""; 1069bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata if (event.value == null || 1079bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata event.value.int32Values == null || 1089bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata event.value.int32Values.size() < 2) return ""; 1099bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata return String.format("Event{source = HAL, keycode = %s, key%s}\n", 1109bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata event.value.int32Values.get(1), 1119bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata event.value.int32Values.get(0) == ACTION_DOWN ? "down" : "up"); 1129bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata } 1139bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata 1149bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata @Override 1159bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) throws RemoteException { 1169bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata synchronized (mInputEventsList) { 1179bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata propValues.forEach(vpv -> mInputEventsList.append(prettyPrint(vpv))); 1189bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata } 1199bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata } 1209bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata 1219bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata @Override 1229bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata public void onPropertySet(VehiclePropValue propValue) {} 1239bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata 1249bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata @Override 1259bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata public void onPropertySetError(int errorCode, int propId, int areaId) {} 1269bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata }; 1279bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata 1283ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata private TextView mInputEventsList; 1293ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata 13031966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev @Override 13131966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev public void onCreate(Bundle savedInstanceState) { 13231966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev super.onCreate(savedInstanceState); 13331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev 13431966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev try { 13531966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev mVehicle = IVehicle.getService(); 13631966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev } catch (NoSuchElementException ex) { 13731966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev throw new RuntimeException("Couldn't connect to " + IVehicle.kInterfaceName, ex); 13831966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev } catch (RemoteException e) { 13931966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev throw new RuntimeException("Failed to connect to IVehicle"); 14031966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev } 14131966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev Log.d(TAG, "Connected to IVehicle service: " + mVehicle); 1423ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata 1433ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata mEventReaderService = EventReaderService.tryGet(); 1443ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata Log.d(TAG, "Key Event Reader service: " + mEventReaderService); 1453ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata if (mEventReaderService != null) { 1463ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata mEventReaderService.registerCallback(mKeypressEventHandler); 1473ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata } 1489bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata 1499bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata SubscribeOptions subscribeOption = new SubscribeOptions(); 1509bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata subscribeOption.propId = HW_KEY_INPUT; 1519bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata subscribeOption.flags = EVENTS_FROM_CAR | EVENTS_FROM_ANDROID; 1529bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata ArrayList<SubscribeOptions> subscribeOptions = new ArrayList<>(); 1539bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata subscribeOptions.add(subscribeOption); 1549bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata try { 1559bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata mVehicle.subscribe(mHalKeyEventHandler, subscribeOptions); 1569bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata } catch (RemoteException e) { 1579bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata Log.e(TAG, "failed to connect to VHAL for key events", e); 1589bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata } 15931966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev } 1600d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev 161a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park @Nullable 162a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park @Override 163a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 164a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park @Nullable Bundle savedInstanceState) { 165d8c22f21348822a0022ec99444ecb062ebfa00dbKeun-young Park View view = inflater.inflate(R.layout.input_test, container, false); 166a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park 1673ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata mInputEventsList = view.findViewById(R.id.events_list); 1683ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata mInputEventsList.setMovementMethod(new ScrollingMovementMethod()); 1693ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata 17031966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev TextView steeringWheelLabel = new TextView(getActivity() /*context*/); 17131966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev steeringWheelLabel.setText(R.string.steering_wheel); 17231966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev steeringWheelLabel.setTextSize(getResources().getDimension(R.dimen.car_title2_size)); 17331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev 174e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev Collections.addAll(mButtons, 175e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev BREAK_LINE, 176e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.home, KeyEvent.KEYCODE_HOME), 177e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.volume_up, KeyEvent.KEYCODE_VOLUME_UP), 178e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.volume_down, KeyEvent.KEYCODE_VOLUME_DOWN), 179e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.volume_mute, KeyEvent.KEYCODE_VOLUME_MUTE), 180e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.voice, KeyEvent.KEYCODE_VOICE_ASSIST), 181e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev BREAK_LINE, 182e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.music, KeyEvent.KEYCODE_MUSIC), 183e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.music_play, KeyEvent.KEYCODE_MEDIA_PLAY), 184e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.music_stop, KeyEvent.KEYCODE_MEDIA_STOP), 185e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.next_song, KeyEvent.KEYCODE_MEDIA_NEXT), 186e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.prev_song, KeyEvent.KEYCODE_MEDIA_PREVIOUS), 187e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.tune_right, KeyEvent.KEYCODE_CHANNEL_UP), 188e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.tune_left, KeyEvent.KEYCODE_CHANNEL_DOWN), 189e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev BREAK_LINE, 190e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev createButton(R.string.call_send, KeyEvent.KEYCODE_CALL), 19131966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev createButton(R.string.call_end, KeyEvent.KEYCODE_ENDCALL), 19231966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev BREAK_LINE, 19331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev steeringWheelLabel, 19431966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev BREAK_LINE, 19531966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev createButton(R.string.sw_left, KeyEvent.KEYCODE_DPAD_LEFT, INSTRUMENT_CLUSTER), 19631966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev createButton(R.string.sw_right, KeyEvent.KEYCODE_DPAD_RIGHT, 19731966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev INSTRUMENT_CLUSTER), 19831966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev createButton(R.string.sw_up, KeyEvent.KEYCODE_DPAD_UP, INSTRUMENT_CLUSTER), 19931966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev createButton(R.string.sw_down, KeyEvent.KEYCODE_DPAD_DOWN, INSTRUMENT_CLUSTER), 20031966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev createButton(R.string.sw_center, KeyEvent.KEYCODE_DPAD_CENTER, 20131966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev INSTRUMENT_CLUSTER), 20231966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev createButton(R.string.sw_back, KeyEvent.KEYCODE_BACK, INSTRUMENT_CLUSTER) 20331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev ); 20431966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev 20531966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev addButtonsToPanel(view.findViewById(R.id.input_buttons), mButtons); 206a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park 207d8c22f21348822a0022ec99444ecb062ebfa00dbKeun-young Park return view; 208a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park } 209a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park 210e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev private Button createButton(@StringRes int textResId, int keyCode) { 21131966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev return createButton(textResId, keyCode, VehicleDisplay.MAIN); 21231966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev } 21331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev 21431966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev private Button createButton(@StringRes int textResId, int keyCode, int targetDisplay) { 215e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev Button button = new Button(getContext()); 216e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev button.setText(getContext().getString(textResId)); 21731966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev button.setTextSize(getResources().getDimension(R.dimen.car_button_text_size)); 21831966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev button.setOnClickListener(v -> onButtonClick(keyCode, targetDisplay)); 219e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev return button; 220e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev } 221e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev 22231966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev private void onButtonClick(int keyCode, int targetDisplay) { 22331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev VehiclePropValue prop = new VehiclePropValue(); 22431966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev prop.prop = sGenerateFakeDataControllingProperty; 22531966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev prop.value.int32Values.addAll(Lists.newArrayList( 2269bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata sKeyPressCommand, HW_KEY_INPUT, keyCode, targetDisplay)); 22731966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev int status; 22831966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev try { 22931966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev status = mVehicle.set(prop); 23031966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev } catch (RemoteException e) { 23131966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev throw new RuntimeException("Failed to inject key press"); 23231966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev } 23331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev 23431966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev if (VehiclePropertyStatus.AVAILABLE != status) { 23531966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev Toast.makeText(getContext(), "Failed to inject key event, status:" + status, 23631966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev Toast.LENGTH_LONG).show(); 237a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park } 238a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park } 239a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park 240a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park @Override 241a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park public void onDestroyView() { 242a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park super.onDestroyView(); 24331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev mButtons.clear(); 2443ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata if (mEventReaderService != null) { 2453ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata mEventReaderService.unregisterCallback(mKeypressEventHandler); 2463ac2057bd91eb506a4731338f724897cc8f449aeEnrico Granata } 2479bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata try { 2489bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata mVehicle.unsubscribe(mHalKeyEventHandler, HW_KEY_INPUT); 2499bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata } catch (RemoteException e) { 2509bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata Log.e(TAG, "failed to remove HAL registration for keypress events", e); 2519bc6ec968099c014c16c57ceee963e4cf5eef1c0Enrico Granata } 252a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park } 253e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev 254e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev private void addButtonsToPanel(LinearLayout root, List<View> buttons) { 255e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev LinearLayout panel = null; 256e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev for (View button : buttons) { 2570d07c76bbc788fba8c77d8e932330ab22ec6ba27Pavel Maltsev if (button == BREAK_LINE || panel == null) { 258e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev panel = new LinearLayout(getContext()); 259e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev panel.setOrientation(LinearLayout.HORIZONTAL); 260e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev root.addView(panel); 261e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev } else { 262e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev panel.addView(button); 26331966496485e3738e6bcfe775885f5cd9b857b22Pavel Maltsev panel.setPadding(0, 10, 10, 0); 264e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev } 265e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev } 266e11ad3ae2a65614c54e37be0a40a83029edcda73Pavel Maltsev } 267a28d7b201584823286f26e21a9f30d07c416eb3eKeun-young Park} 268