blob: a18daed74e62ac1ba67d050ff0aa703c0467a580 [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
Jason Monk0c37ba32014-09-08 15:34:23 -040019import android.app.ActivityManager;
Joe Onorato86f9bd22010-06-30 17:03:42 -040020import android.content.Context;
21import android.content.res.TypedArray;
Jeff Brownac143512012-04-05 18:57:33 -070022import android.hardware.input.InputManager;
Jason Monk0c37ba32014-09-08 15:34:23 -040023import android.media.AudioManager;
Jorim Jaggi7beadfc2014-08-15 18:42:00 +020024import android.os.Bundle;
Joe Onorato86f9bd22010-06-30 17:03:42 -040025import android.os.SystemClock;
Joe Onorato86f9bd22010-06-30 17:03:42 -040026import android.util.AttributeSet;
Daniel Sandler804eb852010-08-31 15:43:50 -040027import android.view.HapticFeedbackConstants;
Jeff Brownbbda99d2010-07-28 15:48:59 -070028import android.view.InputDevice;
Jeff Brown6b53e8d2010-11-10 16:03:06 -080029import android.view.KeyCharacterMap;
Joe Onorato86f9bd22010-06-30 17:03:42 -040030import android.view.KeyEvent;
31import android.view.MotionEvent;
Daniel Sandleraa051d62011-03-01 16:23:57 -050032import android.view.SoundEffectConstants;
Christian Robertson42310962014-09-14 02:14:46 -040033import android.view.View;
Daniel Sandler804eb852010-08-31 15:43:50 -040034import android.view.ViewConfiguration;
John Spurlockde84f0e2013-06-12 12:41:00 -040035import android.view.accessibility.AccessibilityEvent;
Jorim Jaggi7beadfc2014-08-15 18:42:00 +020036import android.view.accessibility.AccessibilityNodeInfo;
Joe Onorato86f9bd22010-06-30 17:03:42 -040037import android.widget.ImageView;
Joe Onorato86f9bd22010-06-30 17:03:42 -040038
39import com.android.systemui.R;
40
Jorim Jaggi7beadfc2014-08-15 18:42:00 +020041import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
42import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
43
Joe Onorato86f9bd22010-06-30 17:03:42 -040044public class KeyButtonView extends ImageView {
Daniel Sandler96f48182011-08-17 09:50:35 -040045
Adrian Rooscde52d72014-05-26 22:21:46 +020046 private long mDownTime;
47 private int mCode;
48 private int mTouchSlop;
Adrian Rooscde52d72014-05-26 22:21:46 +020049 private boolean mSupportsLongpress = true;
Jason Monk0c37ba32014-09-08 15:34:23 -040050 private AudioManager mAudioManager;
Daniel Sandleraa051d62011-03-01 16:23:57 -050051
Adrian Rooscde52d72014-05-26 22:21:46 +020052 private final Runnable mCheckLongPress = new Runnable() {
Daniel Sandler804eb852010-08-31 15:43:50 -040053 public void run() {
Daniel Sandler804eb852010-08-31 15:43:50 -040054 if (isPressed()) {
John Spurlockcd686b52013-06-05 10:13:46 -040055 // Log.d("KeyButtonView", "longpressed: " + this);
Jason Monk815e0572014-08-12 17:26:36 -040056 if (isLongClickable()) {
Daniel Sandlera375c942011-07-29 00:33:53 -040057 // Just an old-fashioned ImageView
58 performLongClick();
Jason Monk815e0572014-08-12 17:26:36 -040059 } else {
60 sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
61 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
Daniel Sandlera375c942011-07-29 00:33:53 -040062 }
Daniel Sandler804eb852010-08-31 15:43:50 -040063 }
64 }
65 };
Joe Onorato86f9bd22010-06-30 17:03:42 -040066
67 public KeyButtonView(Context context, AttributeSet attrs) {
68 this(context, attrs, 0);
69 }
70
71 public KeyButtonView(Context context, AttributeSet attrs, int defStyle) {
72 super(context, attrs);
73
74 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
75 defStyle, 0);
76
77 mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0);
John Spurlock209bede2013-07-17 12:23:27 -040078
Daniel Sandler44a46162011-08-09 16:48:21 -040079 mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true);
Daniel Sandlera375c942011-07-29 00:33:53 -040080
Joe Onorato86f9bd22010-06-30 17:03:42 -040081 a.recycle();
82
Joe Onorato641bad42011-01-06 15:54:23 -080083 setClickable(true);
Daniel Sandleraa051d62011-03-01 16:23:57 -050084 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
Jason Monk0c37ba32014-09-08 15:34:23 -040085 mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
Jorim Jaggi072707d2014-09-15 17:20:08 +020086 setBackground(new KeyButtonRipple(context, this));
Joe Onorato86f9bd22010-06-30 17:03:42 -040087 }
88
Jorim Jaggi7beadfc2014-08-15 18:42:00 +020089 @Override
90 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
91 super.onInitializeAccessibilityNodeInfo(info);
92 if (mCode != 0) {
93 info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, null));
94 if (mSupportsLongpress) {
95 info.addAction(
96 new AccessibilityNodeInfo.AccessibilityAction(ACTION_LONG_CLICK, null));
97 }
98 }
99 }
100
101 @Override
Jorim Jaggib9e290c2014-10-28 19:04:20 +0100102 protected void onWindowVisibilityChanged(int visibility) {
103 super.onWindowVisibilityChanged(visibility);
104 if (visibility != View.VISIBLE) {
105 jumpDrawablesToCurrentState();
106 }
107 }
108
109 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800110 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
Jorim Jaggi7beadfc2014-08-15 18:42:00 +0200111 if (action == ACTION_CLICK && mCode != 0) {
112 sendEvent(KeyEvent.ACTION_DOWN, 0, SystemClock.uptimeMillis());
113 sendEvent(KeyEvent.ACTION_UP, 0);
114 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
115 playSoundEffect(SoundEffectConstants.CLICK);
116 return true;
117 } else if (action == ACTION_LONG_CLICK && mCode != 0 && mSupportsLongpress) {
118 sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
119 sendEvent(KeyEvent.ACTION_UP, 0);
120 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
121 return true;
122 }
Alan Viverettea54956a2015-01-07 16:05:02 -0800123 return super.performAccessibilityActionInternal(action, arguments);
Jorim Jaggi7beadfc2014-08-15 18:42:00 +0200124 }
125
Joe Onorato86f9bd22010-06-30 17:03:42 -0400126 public boolean onTouchEvent(MotionEvent ev) {
127 final int action = ev.getAction();
128 int x, y;
129
130 switch (action) {
131 case MotionEvent.ACTION_DOWN:
John Spurlockcd686b52013-06-05 10:13:46 -0400132 //Log.d("KeyButtonView", "press");
Joe Onorato86f9bd22010-06-30 17:03:42 -0400133 mDownTime = SystemClock.uptimeMillis();
Daniel Sandler44a46162011-08-09 16:48:21 -0400134 setPressed(true);
Jeff Brown98392ef2011-09-12 18:24:59 -0700135 if (mCode != 0) {
136 sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
137 } else {
138 // Provide the same haptic feedback that the system offers for virtual keys.
139 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
140 }
Daniel Sandler44a46162011-08-09 16:48:21 -0400141 if (mSupportsLongpress) {
142 removeCallbacks(mCheckLongPress);
143 postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
Daniel Sandler44a46162011-08-09 16:48:21 -0400144 }
Joe Onorato86f9bd22010-06-30 17:03:42 -0400145 break;
146 case MotionEvent.ACTION_MOVE:
Jeff Brown98392ef2011-09-12 18:24:59 -0700147 x = (int)ev.getX();
148 y = (int)ev.getY();
149 setPressed(x >= -mTouchSlop
150 && x < getWidth() + mTouchSlop
151 && y >= -mTouchSlop
152 && y < getHeight() + mTouchSlop);
Joe Onoratoabb27772010-11-15 13:30:12 -0800153 break;
154 case MotionEvent.ACTION_CANCEL:
155 setPressed(false);
Jeff Brown98392ef2011-09-12 18:24:59 -0700156 if (mCode != 0) {
157 sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
158 }
159 if (mSupportsLongpress) {
160 removeCallbacks(mCheckLongPress);
Joe Onorato86f9bd22010-06-30 17:03:42 -0400161 }
162 break;
163 case MotionEvent.ACTION_UP:
Daniel Sandleraa051d62011-03-01 16:23:57 -0500164 final boolean doIt = isPressed();
Daniel Sandler804eb852010-08-31 15:43:50 -0400165 setPressed(false);
Jeff Brown98392ef2011-09-12 18:24:59 -0700166 if (mCode != 0) {
167 if (doIt) {
168 sendEvent(KeyEvent.ACTION_UP, 0);
169 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
170 playSoundEffect(SoundEffectConstants.CLICK);
Patrick Dubroy5ee1a3d2011-03-02 19:11:19 -0800171 } else {
Jeff Brown98392ef2011-09-12 18:24:59 -0700172 sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
Daniel Sandleraa051d62011-03-01 16:23:57 -0500173 }
Jeff Brown98392ef2011-09-12 18:24:59 -0700174 } else {
175 // no key code, just a regular ImageView
176 if (doIt) {
177 performClick();
178 }
179 }
180 if (mSupportsLongpress) {
181 removeCallbacks(mCheckLongPress);
Joe Onorato86f9bd22010-06-30 17:03:42 -0400182 }
183 break;
184 }
185
186 return true;
187 }
188
Jason Monk0c37ba32014-09-08 15:34:23 -0400189 public void playSoundEffect(int soundConstant) {
190 mAudioManager.playSoundEffect(soundConstant, ActivityManager.getCurrentUser());
191 };
192
Jason Monk815e0572014-08-12 17:26:36 -0400193 public void sendEvent(int action, int flags) {
Jeff Brownbbda99d2010-07-28 15:48:59 -0700194 sendEvent(action, flags, SystemClock.uptimeMillis());
Joe Onorato86f9bd22010-06-30 17:03:42 -0400195 }
196
Jeff Brownbbda99d2010-07-28 15:48:59 -0700197 void sendEvent(int action, int flags, long when) {
Jeff Brown98392ef2011-09-12 18:24:59 -0700198 final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
199 final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
200 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
201 flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
202 InputDevice.SOURCE_KEYBOARD);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700203 InputManager.getInstance().injectInputEvent(ev,
204 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
Joe Onorato86f9bd22010-06-30 17:03:42 -0400205 }
Joe Onorato86f9bd22010-06-30 17:03:42 -0400206}
207
208