Move to Android N-MR1 SDK.
[android_tools.git] / sdk / sources / android-25 / com / android / systemui / statusbar / policy / KeyButtonView.java
blobe6066aaa4c316519c9dc609dfb9809e4417ab525
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.systemui.statusbar.policy;
19 import android.annotation.DrawableRes;
20 import android.annotation.Nullable;
21 import android.app.ActivityManager;
22 import android.content.Context;
23 import android.content.res.Configuration;
24 import android.content.res.TypedArray;
25 import android.graphics.drawable.Drawable;
26 import android.graphics.drawable.Icon;
27 import android.hardware.input.InputManager;
28 import android.media.AudioManager;
29 import android.os.AsyncTask;
30 import android.os.Bundle;
31 import android.os.SystemClock;
32 import android.util.AttributeSet;
33 import android.util.TypedValue;
34 import android.view.HapticFeedbackConstants;
35 import android.view.InputDevice;
36 import android.view.KeyCharacterMap;
37 import android.view.KeyEvent;
38 import android.view.MotionEvent;
39 import android.view.SoundEffectConstants;
40 import android.view.View;
41 import android.view.ViewConfiguration;
42 import android.view.accessibility.AccessibilityEvent;
43 import android.view.accessibility.AccessibilityNodeInfo;
44 import android.widget.ImageView;
46 import com.android.systemui.R;
47 import com.android.systemui.statusbar.phone.ButtonDispatcher;
49 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
50 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
52 public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonInterface {
54 private int mContentDescriptionRes;
55 private long mDownTime;
56 private int mCode;
57 private int mTouchSlop;
58 private boolean mSupportsLongpress = true;
59 private AudioManager mAudioManager;
60 private boolean mGestureAborted;
61 private boolean mLongClicked;
62 private OnClickListener mOnClickListener;
64 private final Runnable mCheckLongPress = new Runnable() {
65 public void run() {
66 if (isPressed()) {
67 // Log.d("KeyButtonView", "longpressed: " + this);
68 if (isLongClickable()) {
69 // Just an old-fashioned ImageView
70 performLongClick();
71 mLongClicked = true;
72 } else if (mSupportsLongpress) {
73 sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
74 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
75 mLongClicked = true;
81 public KeyButtonView(Context context, AttributeSet attrs) {
82 this(context, attrs, 0);
85 public KeyButtonView(Context context, AttributeSet attrs, int defStyle) {
86 super(context, attrs);
88 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
89 defStyle, 0);
91 mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0);
93 mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true);
95 TypedValue value = new TypedValue();
96 if (a.getValue(R.styleable.KeyButtonView_android_contentDescription, value)) {
97 mContentDescriptionRes = value.resourceId;
100 a.recycle();
103 setClickable(true);
104 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
105 mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
106 setBackground(new KeyButtonRipple(context, this));
109 public void setCode(int code) {
110 mCode = code;
113 @Override
114 public void setOnClickListener(OnClickListener onClickListener) {
115 super.setOnClickListener(onClickListener);
116 mOnClickListener = onClickListener;
119 public void loadAsync(String uri) {
120 new AsyncTask<String, Void, Drawable>() {
121 @Override
122 protected Drawable doInBackground(String... params) {
123 return Icon.createWithContentUri(params[0]).loadDrawable(mContext);
126 @Override
127 protected void onPostExecute(Drawable drawable) {
128 setImageDrawable(drawable);
130 }.execute(uri);
133 @Override
134 protected void onConfigurationChanged(Configuration newConfig) {
135 super.onConfigurationChanged(newConfig);
137 if (mContentDescriptionRes != 0) {
138 setContentDescription(mContext.getString(mContentDescriptionRes));
142 @Override
143 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
144 super.onInitializeAccessibilityNodeInfo(info);
145 if (mCode != 0) {
146 info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, null));
147 if (mSupportsLongpress || isLongClickable()) {
148 info.addAction(
149 new AccessibilityNodeInfo.AccessibilityAction(ACTION_LONG_CLICK, null));
154 @Override
155 protected void onWindowVisibilityChanged(int visibility) {
156 super.onWindowVisibilityChanged(visibility);
157 if (visibility != View.VISIBLE) {
158 jumpDrawablesToCurrentState();
162 @Override
163 public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
164 if (action == ACTION_CLICK && mCode != 0) {
165 sendEvent(KeyEvent.ACTION_DOWN, 0, SystemClock.uptimeMillis());
166 sendEvent(KeyEvent.ACTION_UP, 0);
167 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
168 playSoundEffect(SoundEffectConstants.CLICK);
169 return true;
170 } else if (action == ACTION_LONG_CLICK && mCode != 0) {
171 sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
172 sendEvent(KeyEvent.ACTION_UP, 0);
173 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
174 return true;
176 return super.performAccessibilityActionInternal(action, arguments);
179 public boolean onTouchEvent(MotionEvent ev) {
180 final int action = ev.getAction();
181 int x, y;
182 if (action == MotionEvent.ACTION_DOWN) {
183 mGestureAborted = false;
185 if (mGestureAborted) {
186 return false;
189 switch (action) {
190 case MotionEvent.ACTION_DOWN:
191 mDownTime = SystemClock.uptimeMillis();
192 mLongClicked = false;
193 setPressed(true);
194 if (mCode != 0) {
195 sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
196 } else {
197 // Provide the same haptic feedback that the system offers for virtual keys.
198 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
200 playSoundEffect(SoundEffectConstants.CLICK);
201 removeCallbacks(mCheckLongPress);
202 postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
203 break;
204 case MotionEvent.ACTION_MOVE:
205 x = (int)ev.getX();
206 y = (int)ev.getY();
207 setPressed(x >= -mTouchSlop
208 && x < getWidth() + mTouchSlop
209 && y >= -mTouchSlop
210 && y < getHeight() + mTouchSlop);
211 break;
212 case MotionEvent.ACTION_CANCEL:
213 setPressed(false);
214 if (mCode != 0) {
215 sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
217 removeCallbacks(mCheckLongPress);
218 break;
219 case MotionEvent.ACTION_UP:
220 final boolean doIt = isPressed() && !mLongClicked;
221 setPressed(false);
222 if (mCode != 0) {
223 if (doIt) {
224 sendEvent(KeyEvent.ACTION_UP, 0);
225 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
226 } else {
227 sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
229 } else {
230 // no key code, just a regular ImageView
231 if (doIt && mOnClickListener != null) {
232 mOnClickListener.onClick(this);
233 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
236 removeCallbacks(mCheckLongPress);
237 break;
240 return true;
243 public void playSoundEffect(int soundConstant) {
244 mAudioManager.playSoundEffect(soundConstant, ActivityManager.getCurrentUser());
247 public void sendEvent(int action, int flags) {
248 sendEvent(action, flags, SystemClock.uptimeMillis());
251 void sendEvent(int action, int flags, long when) {
252 final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
253 final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
254 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
255 flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
256 InputDevice.SOURCE_KEYBOARD);
257 InputManager.getInstance().injectInputEvent(ev,
258 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
261 @Override
262 public void abortCurrentGesture() {
263 setPressed(false);
264 mGestureAborted = true;
267 @Override
268 public void setImageResource(@DrawableRes int resId) {
269 super.setImageResource(resId);
272 @Override
273 public void setImageDrawable(@Nullable Drawable drawable) {
274 super.setImageDrawable(drawable);
277 @Override
278 public void setLandscape(boolean landscape) {
279 //no op
282 @Override
283 public void setCarMode(boolean carMode) {
284 // no op