blob: 9923ec9d8a75f64acfff04297ff634de3c15cfb2 [file] [log] [blame]
Joe Onorato86f9bd22010-06-30 17:03:42 -04001/*
2 * Copyright (C) 2008 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
Joe Onoratofd52b182010-11-10 18:00:52 -080017package com.android.systemui.statusbar.policy;
Joe Onorato86f9bd22010-06-30 17:03:42 -040018
Charles Chenf7150f62018-10-01 14:42:07 +080019import static android.view.Display.INVALID_DISPLAY;
Siarhei Vishniakou9f70d022019-03-15 17:03:22 -070020import static android.view.KeyEvent.KEYCODE_UNKNOWN;
Winson Chung661d5f92018-05-21 18:41:39 -070021import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
22import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
23
Jason Monk0c37ba32014-09-08 15:34:23 -040024import android.app.ActivityManager;
Joe Onorato86f9bd22010-06-30 17:03:42 -040025import android.content.Context;
Adrian Roos3bab5152015-10-16 16:51:04 -070026import android.content.res.Configuration;
Joe Onorato86f9bd22010-06-30 17:03:42 -040027import android.content.res.TypedArray;
Jason Monk8457ad82016-01-24 10:15:55 -050028import android.graphics.drawable.Drawable;
29import android.graphics.drawable.Icon;
Jeff Brownac143512012-04-05 18:57:33 -070030import android.hardware.input.InputManager;
Jason Monk0c37ba32014-09-08 15:34:23 -040031import android.media.AudioManager;
Jason Monkcbf591b2017-03-31 15:42:27 -040032import android.metrics.LogMaker;
Jason Monk8457ad82016-01-24 10:15:55 -050033import android.os.AsyncTask;
Jorim Jaggi7beadfc2014-08-15 18:42:00 +020034import android.os.Bundle;
Joe Onorato86f9bd22010-06-30 17:03:42 -040035import android.os.SystemClock;
Joe Onorato86f9bd22010-06-30 17:03:42 -040036import android.util.AttributeSet;
Matthew Ng0ceca182019-01-02 17:18:32 -080037import android.util.Log;
Adrian Roos3bab5152015-10-16 16:51:04 -070038import android.util.TypedValue;
Daniel Sandler804eb852010-08-31 15:43:50 -040039import android.view.HapticFeedbackConstants;
Jeff Brownbbda99d2010-07-28 15:48:59 -070040import android.view.InputDevice;
Jeff Brown6b53e8d2010-11-10 16:03:06 -080041import android.view.KeyCharacterMap;
Joe Onorato86f9bd22010-06-30 17:03:42 -040042import android.view.KeyEvent;
43import android.view.MotionEvent;
Daniel Sandleraa051d62011-03-01 16:23:57 -050044import android.view.SoundEffectConstants;
Christian Robertson42310962014-09-14 02:14:46 -040045import android.view.View;
Daniel Sandler804eb852010-08-31 15:43:50 -040046import android.view.ViewConfiguration;
John Spurlockde84f0e2013-06-12 12:41:00 -040047import android.view.accessibility.AccessibilityEvent;
Jorim Jaggi7beadfc2014-08-15 18:42:00 +020048import android.view.accessibility.AccessibilityNodeInfo;
Joe Onorato86f9bd22010-06-30 17:03:42 -040049import android.widget.ImageView;
Gus Prevasab336792018-11-14 13:52:20 -050050
Mady Mellor390bff42019-04-05 15:09:01 -070051import com.android.internal.annotations.VisibleForTesting;
Jason Monkcbf591b2017-03-31 15:42:27 -040052import com.android.internal.logging.MetricsLogger;
53import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
54import com.android.systemui.Dependency;
Joe Onorato86f9bd22010-06-30 17:03:42 -040055import com.android.systemui.R;
Mady Mellor390bff42019-04-05 15:09:01 -070056import com.android.systemui.bubbles.BubbleController;
Jason Monk197f4db2016-08-26 13:28:20 -040057import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
Gus Prevasab336792018-11-14 13:52:20 -050058import com.android.systemui.recents.OverviewProxyService;
Matthew Ngf29ad752018-04-26 11:24:05 -070059import com.android.systemui.shared.system.NavigationBarCompat;
Joe Onorato86f9bd22010-06-30 17:03:42 -040060
Jason Monk197f4db2016-08-26 13:28:20 -040061public class KeyButtonView extends ImageView implements ButtonInterface {
Winson Chung58bd4392018-02-08 17:53:26 -080062 private static final String TAG = KeyButtonView.class.getSimpleName();
Daniel Sandler96f48182011-08-17 09:50:35 -040063
Jason Monk6c1e6ca2017-03-30 14:12:13 -040064 private final boolean mPlaySounds;
Adrian Roos3bab5152015-10-16 16:51:04 -070065 private int mContentDescriptionRes;
Adrian Rooscde52d72014-05-26 22:21:46 +020066 private long mDownTime;
67 private int mCode;
Matthew Ng83ef2f82018-01-29 16:11:40 -080068 private int mTouchDownX;
69 private int mTouchDownY;
Matthew Ng9a223632018-03-30 16:47:22 -070070 private boolean mIsVertical;
Jason Monk0c37ba32014-09-08 15:34:23 -040071 private AudioManager mAudioManager;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070072 private boolean mGestureAborted;
Jorim Jaggi053f2182015-11-24 16:07:55 -080073 private boolean mLongClicked;
Jorim Jaggi05bce152016-08-25 18:14:14 -070074 private OnClickListener mOnClickListener;
Jorim Jaggi40db0292016-06-27 17:58:03 -070075 private final KeyButtonRipple mRipple;
Matthew Ng83ef2f82018-01-29 16:11:40 -080076 private final OverviewProxyService mOverviewProxyService;
Jason Monkcbf591b2017-03-31 15:42:27 -040077 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
Mady Mellor390bff42019-04-05 15:09:01 -070078 private final InputManager mInputManager;
Daniel Sandleraa051d62011-03-01 16:23:57 -050079
Adrian Rooscde52d72014-05-26 22:21:46 +020080 private final Runnable mCheckLongPress = new Runnable() {
Daniel Sandler804eb852010-08-31 15:43:50 -040081 public void run() {
Matthew Ng3aa0dde2018-03-13 14:20:54 -070082 if (isPressed()) {
John Spurlockcd686b52013-06-05 10:13:46 -040083 // Log.d("KeyButtonView", "longpressed: " + this);
Jason Monk815e0572014-08-12 17:26:36 -040084 if (isLongClickable()) {
Daniel Sandlera375c942011-07-29 00:33:53 -040085 // Just an old-fashioned ImageView
86 performLongClick();
Jorim Jaggi053f2182015-11-24 16:07:55 -080087 mLongClicked = true;
Siarhei Vishniakoud41b41f2019-03-19 13:52:50 -070088 } else {
Jason Monk815e0572014-08-12 17:26:36 -040089 sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
90 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
Jorim Jaggi053f2182015-11-24 16:07:55 -080091 mLongClicked = true;
Daniel Sandlera375c942011-07-29 00:33:53 -040092 }
Daniel Sandler804eb852010-08-31 15:43:50 -040093 }
94 }
95 };
Joe Onorato86f9bd22010-06-30 17:03:42 -040096
97 public KeyButtonView(Context context, AttributeSet attrs) {
98 this(context, attrs, 0);
99 }
100
101 public KeyButtonView(Context context, AttributeSet attrs, int defStyle) {
Mady Mellor390bff42019-04-05 15:09:01 -0700102 this(context, attrs, defStyle, InputManager.getInstance());
103 }
104
105 @VisibleForTesting
106 public KeyButtonView(Context context, AttributeSet attrs, int defStyle, InputManager manager) {
Joe Onorato86f9bd22010-06-30 17:03:42 -0400107 super(context, attrs);
108
109 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
110 defStyle, 0);
111
Siarhei Vishniakou9f70d022019-03-15 17:03:22 -0700112 mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, KEYCODE_UNKNOWN);
John Spurlock209bede2013-07-17 12:23:27 -0400113
Jason Monk6c1e6ca2017-03-30 14:12:13 -0400114 mPlaySounds = a.getBoolean(R.styleable.KeyButtonView_playSound, true);
Daniel Sandlera375c942011-07-29 00:33:53 -0400115
Adrian Roos3bab5152015-10-16 16:51:04 -0700116 TypedValue value = new TypedValue();
117 if (a.getValue(R.styleable.KeyButtonView_android_contentDescription, value)) {
118 mContentDescriptionRes = value.resourceId;
119 }
120
Joe Onorato86f9bd22010-06-30 17:03:42 -0400121 a.recycle();
122
Joe Onorato641bad42011-01-06 15:54:23 -0800123 setClickable(true);
Jason Monk0c37ba32014-09-08 15:34:23 -0400124 mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
Jorim Jaggi40db0292016-06-27 17:58:03 -0700125
126 mRipple = new KeyButtonRipple(context, this);
Matthew Ng83ef2f82018-01-29 16:11:40 -0800127 mOverviewProxyService = Dependency.get(OverviewProxyService.class);
Mady Mellor390bff42019-04-05 15:09:01 -0700128 mInputManager = manager;
Jorim Jaggi40db0292016-06-27 17:58:03 -0700129 setBackground(mRipple);
Winson Chung661d5f92018-05-21 18:41:39 -0700130 forceHasOverlappingRendering(false);
Joe Onorato86f9bd22010-06-30 17:03:42 -0400131 }
132
Jason Monk9262c942017-07-28 14:35:13 -0400133 @Override
134 public boolean isClickable() {
Siarhei Vishniakou9f70d022019-03-15 17:03:22 -0700135 return mCode != KEYCODE_UNKNOWN || super.isClickable();
Jason Monk9262c942017-07-28 14:35:13 -0400136 }
137
Jason Monk8457ad82016-01-24 10:15:55 -0500138 public void setCode(int code) {
139 mCode = code;
140 }
141
Jorim Jaggi05bce152016-08-25 18:14:14 -0700142 @Override
143 public void setOnClickListener(OnClickListener onClickListener) {
144 super.setOnClickListener(onClickListener);
145 mOnClickListener = onClickListener;
146 }
147
Jason Monkea05f872017-01-24 19:43:36 -0500148 public void loadAsync(Icon icon) {
149 new AsyncTask<Icon, Void, Drawable>() {
Jason Monk8457ad82016-01-24 10:15:55 -0500150 @Override
Jason Monkea05f872017-01-24 19:43:36 -0500151 protected Drawable doInBackground(Icon... params) {
152 return params[0].loadDrawable(mContext);
Jason Monk8457ad82016-01-24 10:15:55 -0500153 }
154
155 @Override
156 protected void onPostExecute(Drawable drawable) {
157 setImageDrawable(drawable);
158 }
Jason Monkea05f872017-01-24 19:43:36 -0500159 }.execute(icon);
Jason Monk8457ad82016-01-24 10:15:55 -0500160 }
161
Jorim Jaggi7beadfc2014-08-15 18:42:00 +0200162 @Override
Adrian Roos3bab5152015-10-16 16:51:04 -0700163 protected void onConfigurationChanged(Configuration newConfig) {
164 super.onConfigurationChanged(newConfig);
165
166 if (mContentDescriptionRes != 0) {
167 setContentDescription(mContext.getString(mContentDescriptionRes));
168 }
169 }
170
171 @Override
Jorim Jaggi7beadfc2014-08-15 18:42:00 +0200172 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
173 super.onInitializeAccessibilityNodeInfo(info);
Siarhei Vishniakou9f70d022019-03-15 17:03:22 -0700174 if (mCode != KEYCODE_UNKNOWN) {
Jorim Jaggi7beadfc2014-08-15 18:42:00 +0200175 info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, null));
Siarhei Vishniakoud41b41f2019-03-19 13:52:50 -0700176 if (isLongClickable()) {
Jorim Jaggi7beadfc2014-08-15 18:42:00 +0200177 info.addAction(
178 new AccessibilityNodeInfo.AccessibilityAction(ACTION_LONG_CLICK, null));
179 }
180 }
181 }
182
183 @Override
Jorim Jaggib9e290c2014-10-28 19:04:20 +0100184 protected void onWindowVisibilityChanged(int visibility) {
185 super.onWindowVisibilityChanged(visibility);
186 if (visibility != View.VISIBLE) {
187 jumpDrawablesToCurrentState();
188 }
189 }
190
191 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800192 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
Siarhei Vishniakou9f70d022019-03-15 17:03:22 -0700193 if (action == ACTION_CLICK && mCode != KEYCODE_UNKNOWN) {
Jorim Jaggi7beadfc2014-08-15 18:42:00 +0200194 sendEvent(KeyEvent.ACTION_DOWN, 0, SystemClock.uptimeMillis());
195 sendEvent(KeyEvent.ACTION_UP, 0);
196 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
197 playSoundEffect(SoundEffectConstants.CLICK);
198 return true;
Siarhei Vishniakou9f70d022019-03-15 17:03:22 -0700199 } else if (action == ACTION_LONG_CLICK && mCode != KEYCODE_UNKNOWN) {
Jorim Jaggi7beadfc2014-08-15 18:42:00 +0200200 sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
201 sendEvent(KeyEvent.ACTION_UP, 0);
202 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
203 return true;
204 }
Alan Viverettea54956a2015-01-07 16:05:02 -0800205 return super.performAccessibilityActionInternal(action, arguments);
Jorim Jaggi7beadfc2014-08-15 18:42:00 +0200206 }
207
Siarhei Vishniakou311748a2019-03-15 17:08:44 -0700208 @Override
Joe Onorato86f9bd22010-06-30 17:03:42 -0400209 public boolean onTouchEvent(MotionEvent ev) {
Winson Chungd95a2252018-04-04 17:02:29 +0000210 final boolean showSwipeUI = mOverviewProxyService.shouldShowSwipeUpUI();
Joe Onorato86f9bd22010-06-30 17:03:42 -0400211 final int action = ev.getAction();
212 int x, y;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700213 if (action == MotionEvent.ACTION_DOWN) {
214 mGestureAborted = false;
215 }
216 if (mGestureAborted) {
Matthew Ng3aa0dde2018-03-13 14:20:54 -0700217 setPressed(false);
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700218 return false;
219 }
Joe Onorato86f9bd22010-06-30 17:03:42 -0400220
221 switch (action) {
222 case MotionEvent.ACTION_DOWN:
223 mDownTime = SystemClock.uptimeMillis();
Jorim Jaggi053f2182015-11-24 16:07:55 -0800224 mLongClicked = false;
Matthew Ng3aa0dde2018-03-13 14:20:54 -0700225 setPressed(true);
Matthew Ng2ea93b72018-03-14 19:43:18 +0000226
227 // Use raw X and Y to detect gestures in case a parent changes the x and y values
228 mTouchDownX = (int) ev.getRawX();
229 mTouchDownY = (int) ev.getRawY();
Siarhei Vishniakou9f70d022019-03-15 17:03:22 -0700230 if (mCode != KEYCODE_UNKNOWN) {
Jeff Brown98392ef2011-09-12 18:24:59 -0700231 sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
232 } else {
233 // Provide the same haptic feedback that the system offers for virtual keys.
234 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
235 }
Winson Chungd95a2252018-04-04 17:02:29 +0000236 if (!showSwipeUI) {
Matthew Ng83ef2f82018-01-29 16:11:40 -0800237 playSoundEffect(SoundEffectConstants.CLICK);
238 }
Jorim Jaggi7e6571f2015-06-25 11:52:48 -0700239 removeCallbacks(mCheckLongPress);
240 postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
Joe Onorato86f9bd22010-06-30 17:03:42 -0400241 break;
242 case MotionEvent.ACTION_MOVE:
Matthew Ng2ea93b72018-03-14 19:43:18 +0000243 x = (int)ev.getRawX();
244 y = (int)ev.getRawY();
Matthew Ng9a223632018-03-30 16:47:22 -0700245
Matthew Ngf29ad752018-04-26 11:24:05 -0700246 boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) > (mIsVertical
247 ? NavigationBarCompat.getQuickScrubTouchSlopPx()
248 : NavigationBarCompat.getQuickStepTouchSlopPx());
249 boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) > (mIsVertical
250 ? NavigationBarCompat.getQuickStepTouchSlopPx()
251 : NavigationBarCompat.getQuickScrubTouchSlopPx());
Matthew Ng83ef2f82018-01-29 16:11:40 -0800252 if (exceededTouchSlopX || exceededTouchSlopY) {
Matthew Ng2fb239c2018-02-28 11:55:52 -0800253 // When quick step is enabled, prevent animating the ripple triggered by
254 // setPressed and decide to run it on touch up
Matthew Ng3aa0dde2018-03-13 14:20:54 -0700255 setPressed(false);
Matthew Ng83ef2f82018-01-29 16:11:40 -0800256 removeCallbacks(mCheckLongPress);
257 }
Joe Onoratoabb27772010-11-15 13:30:12 -0800258 break;
259 case MotionEvent.ACTION_CANCEL:
260 setPressed(false);
Siarhei Vishniakou9f70d022019-03-15 17:03:22 -0700261 if (mCode != KEYCODE_UNKNOWN) {
Jeff Brown98392ef2011-09-12 18:24:59 -0700262 sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
263 }
Jorim Jaggi7e6571f2015-06-25 11:52:48 -0700264 removeCallbacks(mCheckLongPress);
Joe Onorato86f9bd22010-06-30 17:03:42 -0400265 break;
266 case MotionEvent.ACTION_UP:
Matthew Ng3aa0dde2018-03-13 14:20:54 -0700267 final boolean doIt = isPressed() && !mLongClicked;
268 setPressed(false);
Matthew Ng5c0592e2018-03-08 14:51:36 -0800269 final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
Winson Chungd95a2252018-04-04 17:02:29 +0000270 if (showSwipeUI) {
Matthew Ng83ef2f82018-01-29 16:11:40 -0800271 if (doIt) {
Matthew Ng0e1e0f62018-03-30 12:09:31 -0700272 // Apply haptic feedback on touch up since there is none on touch down
273 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
Matthew Ng83ef2f82018-01-29 16:11:40 -0800274 playSoundEffect(SoundEffectConstants.CLICK);
275 }
Matthew Ng5c0592e2018-03-08 14:51:36 -0800276 } else if (doHapticFeedback && !mLongClicked) {
Matthew Ng83ef2f82018-01-29 16:11:40 -0800277 // Always send a release ourselves because it doesn't seem to be sent elsewhere
278 // and it feels weird to sometimes get a release haptic and other times not.
Jason Monk058cbcc2017-07-06 15:38:19 -0400279 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
280 }
Siarhei Vishniakou9f70d022019-03-15 17:03:22 -0700281 if (mCode != KEYCODE_UNKNOWN) {
Jeff Brown98392ef2011-09-12 18:24:59 -0700282 if (doIt) {
283 sendEvent(KeyEvent.ACTION_UP, 0);
284 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
Patrick Dubroy5ee1a3d2011-03-02 19:11:19 -0800285 } else {
Jeff Brown98392ef2011-09-12 18:24:59 -0700286 sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
Daniel Sandleraa051d62011-03-01 16:23:57 -0500287 }
Jeff Brown98392ef2011-09-12 18:24:59 -0700288 } else {
289 // no key code, just a regular ImageView
Jorim Jaggi05bce152016-08-25 18:14:14 -0700290 if (doIt && mOnClickListener != null) {
291 mOnClickListener.onClick(this);
292 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
Jeff Brown98392ef2011-09-12 18:24:59 -0700293 }
294 }
Jorim Jaggi7e6571f2015-06-25 11:52:48 -0700295 removeCallbacks(mCheckLongPress);
Joe Onorato86f9bd22010-06-30 17:03:42 -0400296 break;
297 }
298
299 return true;
300 }
301
Jason Monk0c37ba32014-09-08 15:34:23 -0400302 public void playSoundEffect(int soundConstant) {
Jason Monk6c1e6ca2017-03-30 14:12:13 -0400303 if (!mPlaySounds) return;
Jason Monk0c37ba32014-09-08 15:34:23 -0400304 mAudioManager.playSoundEffect(soundConstant, ActivityManager.getCurrentUser());
Jason Monk6c1e6ca2017-03-30 14:12:13 -0400305 }
Jason Monk0c37ba32014-09-08 15:34:23 -0400306
Jason Monk815e0572014-08-12 17:26:36 -0400307 public void sendEvent(int action, int flags) {
Jeff Brownbbda99d2010-07-28 15:48:59 -0700308 sendEvent(action, flags, SystemClock.uptimeMillis());
Joe Onorato86f9bd22010-06-30 17:03:42 -0400309 }
310
Siarhei Vishniakou311748a2019-03-15 17:08:44 -0700311 private void sendEvent(int action, int flags, long when) {
Jason Monkcbf591b2017-03-31 15:42:27 -0400312 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
313 .setType(MetricsEvent.TYPE_ACTION)
314 .setSubtype(mCode)
315 .addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
316 .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
Matthew Ng0ceca182019-01-02 17:18:32 -0800317 // TODO(b/122195391): Added logs to make sure sysui is sending back button events
318 if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
319 Log.i(TAG, "Back button event: " + KeyEvent.actionToString(action));
Winson Chung04ff8bda2019-04-02 15:08:59 -0700320 if (action == MotionEvent.ACTION_UP) {
321 mOverviewProxyService.notifyBackAction((flags & KeyEvent.FLAG_CANCELED) == 0,
322 -1, -1, true /* isButton */, false /* gestureSwipeLeft */);
323 }
Matthew Ng0ceca182019-01-02 17:18:32 -0800324 }
Jeff Brown98392ef2011-09-12 18:24:59 -0700325 final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
326 final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
327 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
328 flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
329 InputDevice.SOURCE_KEYBOARD);
Charles Chenf7150f62018-10-01 14:42:07 +0800330
Mady Mellor390bff42019-04-05 15:09:01 -0700331 int displayId = INVALID_DISPLAY;
332
333 // Make KeyEvent work on multi-display environment
334 if (getDisplay() != null) {
335 displayId = getDisplay().getDisplayId();
Charles Chenf7150f62018-10-01 14:42:07 +0800336 }
Mady Mellor390bff42019-04-05 15:09:01 -0700337 // Bubble controller will give us a valid display id if it should get the back event
338 BubbleController bubbleController = Dependency.get(BubbleController.class);
339 int bubbleDisplayId = bubbleController.getExpandedDisplayId(mContext);
340 if (mCode == KeyEvent.KEYCODE_BACK && bubbleDisplayId != INVALID_DISPLAY) {
341 displayId = bubbleDisplayId;
342 }
343 if (displayId != INVALID_DISPLAY) {
344 ev.setDisplayId(displayId);
345 }
346 mInputManager.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
Joe Onorato86f9bd22010-06-30 17:03:42 -0400347 }
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700348
Annie Chin1ea49352016-05-27 15:23:35 -0700349 @Override
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700350 public void abortCurrentGesture() {
351 setPressed(false);
Matthew Ng3aa0dde2018-03-13 14:20:54 -0700352 mRipple.abortDelayedRipple();
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700353 mGestureAborted = true;
354 }
Annie Chin1ea49352016-05-27 15:23:35 -0700355
356 @Override
Jorim Jaggi40db0292016-06-27 17:58:03 -0700357 public void setDarkIntensity(float darkIntensity) {
358 Drawable drawable = getDrawable();
359 if (drawable != null) {
360 ((KeyButtonDrawable) getDrawable()).setDarkIntensity(darkIntensity);
Annie Chin1ea49352016-05-27 15:23:35 -0700361
Jorim Jaggi40db0292016-06-27 17:58:03 -0700362 // Since we reuse the same drawable for multiple views, we need to invalidate the view
363 // manually.
364 invalidate();
365 }
366 mRipple.setDarkIntensity(darkIntensity);
Annie Chin1ea49352016-05-27 15:23:35 -0700367 }
Annie Chin6fc46002016-07-07 18:38:12 -0700368
369 @Override
Matthew Nga8f24262017-12-19 11:54:24 -0800370 public void setDelayTouchFeedback(boolean shouldDelay) {
Matthew Ng3aa0dde2018-03-13 14:20:54 -0700371 mRipple.setDelayTouchFeedback(shouldDelay);
Matthew Nga8f24262017-12-19 11:54:24 -0800372 }
373
374 @Override
Xiaohui Chen40e978e2016-11-29 15:10:04 -0800375 public void setVertical(boolean vertical) {
Matthew Ng9a223632018-03-30 16:47:22 -0700376 mIsVertical = vertical;
Annie Chin6fc46002016-07-07 18:38:12 -0700377 }
Joe Onorato86f9bd22010-06-30 17:03:42 -0400378}
379
380