KeyButtonView.java revision c638c1eb1bbed67d7d8f0d43f39137d766366f54
1/* 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 17package com.android.systemui.statusbar.policy; 18 19import android.animation.Animator; 20import android.animation.AnimatorSet; 21import android.animation.ObjectAnimator; 22import android.content.Context; 23import android.content.res.TypedArray; 24import android.graphics.drawable.AnimationDrawable; 25import android.graphics.drawable.Drawable; 26import android.graphics.Canvas; 27import android.graphics.RectF; 28import android.os.RemoteException; 29import android.os.SystemClock; 30import android.os.ServiceManager; 31import android.util.AttributeSet; 32import android.util.Slog; 33import android.view.accessibility.AccessibilityEvent; 34import android.view.HapticFeedbackConstants; 35import android.view.IWindowManager; 36import android.view.InputDevice; 37import android.view.KeyCharacterMap; 38import android.view.KeyEvent; 39import android.view.MotionEvent; 40import android.view.SoundEffectConstants; 41import android.view.View; 42import android.view.ViewConfiguration; 43import android.view.ViewGroup; 44import android.widget.ImageView; 45import android.widget.RemoteViews.RemoteView; 46 47import com.android.systemui.R; 48 49public class KeyButtonView extends ImageView { 50 private static final String TAG = "StatusBar.KeyButtonView"; 51 52 final float GLOW_MAX_SCALE_FACTOR = 1.8f; 53 54 IWindowManager mWindowManager; 55 long mDownTime; 56 boolean mSending; 57 int mCode; 58 int mRepeat; 59 int mTouchSlop; 60 Drawable mGlowBG; 61 float mGlowAlpha = 0f, mGlowScale = 1f, mDrawingAlpha = 1f; 62 boolean mSupportsLongpress = true; 63 RectF mRect = new RectF(0f,0f,0f,0f); 64 65 Runnable mCheckLongPress = new Runnable() { 66 public void run() { 67 if (isPressed()) { 68 // Slog.d("KeyButtonView", "longpressed: " + this); 69 if (mCode != 0) { 70 mRepeat++; 71 sendEvent(KeyEvent.ACTION_DOWN, 72 KeyEvent.FLAG_FROM_SYSTEM 73 | KeyEvent.FLAG_VIRTUAL_HARD_KEY 74 | KeyEvent.FLAG_LONG_PRESS); 75 76 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 77 } else { 78 // Just an old-fashioned ImageView 79 performLongClick(); 80 } 81 } 82 } 83 }; 84 85 public KeyButtonView(Context context, AttributeSet attrs) { 86 this(context, attrs, 0); 87 } 88 89 public KeyButtonView(Context context, AttributeSet attrs, int defStyle) { 90 super(context, attrs); 91 92 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView, 93 defStyle, 0); 94 95 mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0); 96 97 mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true); 98 99 mGlowBG = a.getDrawable(R.styleable.KeyButtonView_glowBackground); 100 if (mGlowBG != null) { 101 mDrawingAlpha = 0.5f; 102 } 103 104 a.recycle(); 105 106 mWindowManager = IWindowManager.Stub.asInterface( 107 ServiceManager.getService(Context.WINDOW_SERVICE)); 108 109 setClickable(true); 110 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 111 } 112 113 @Override 114 protected void onDraw(Canvas canvas) { 115 if (mGlowBG != null) { 116 canvas.save(); 117 final int w = getWidth(); 118 final int h = getHeight(); 119 canvas.scale(mGlowScale, mGlowScale, w*0.5f, h*0.5f); 120 mGlowBG.setBounds(0, 0, w, h); 121 mGlowBG.setAlpha((int)(mGlowAlpha * 255)); 122 mGlowBG.draw(canvas); 123 canvas.restore(); 124 mRect.right = w; 125 mRect.bottom = h; 126 canvas.saveLayerAlpha(mRect, (int)(mDrawingAlpha * 255), Canvas.ALL_SAVE_FLAG); 127 } 128 super.onDraw(canvas); 129 if (mGlowBG != null) { 130 canvas.restore(); 131 } 132 } 133 134 public float getDrawingAlpha() { 135 if (mGlowBG == null) return 0; 136 return mDrawingAlpha; 137 } 138 139 public void setDrawingAlpha(float x) { 140 if (mGlowBG == null) return; 141 mDrawingAlpha = x; 142 invalidate(); 143 } 144 145 public float getGlowAlpha() { 146 if (mGlowBG == null) return 0; 147 return mGlowAlpha; 148 } 149 150 public void setGlowAlpha(float x) { 151 if (mGlowBG == null) return; 152 mGlowAlpha = x; 153 invalidate(); 154 } 155 156 public float getGlowScale() { 157 if (mGlowBG == null) return 0; 158 return mGlowScale; 159 } 160 161 public void setGlowScale(float x) { 162 if (mGlowBG == null) return; 163 mGlowScale = x; 164 final float w = getWidth(); 165 final float h = getHeight(); 166 if (GLOW_MAX_SCALE_FACTOR <= 1.0f) { 167 // this only works if we know the glow will never leave our bounds 168 invalidate(); 169 } else { 170 final float rx = (w * (GLOW_MAX_SCALE_FACTOR - 1.0f)) / 2.0f + 1.0f; 171 final float ry = (h * (GLOW_MAX_SCALE_FACTOR - 1.0f)) / 2.0f + 1.0f; 172 com.android.systemui.SwipeHelper.invalidateGlobalRegion( 173 this, 174 new RectF(getLeft() - rx, 175 getTop() - ry, 176 getRight() + rx, 177 getBottom() + ry)); 178 179 // also invalidate our immediate parent to help avoid situations where nearby glows 180 // interfere 181 ((View)getParent()).invalidate(); 182 } 183 } 184 185 public void setPressed(boolean pressed) { 186 if (mGlowBG != null) { 187 if (pressed != isPressed()) { 188 AnimatorSet as = new AnimatorSet(); 189 if (pressed) { 190 if (mGlowScale < 1.7f) mGlowScale = 1.7f; 191 if (mGlowAlpha < 0.5f) mGlowAlpha = 0.5f; 192 setDrawingAlpha(1f); 193 as.playTogether( 194 ObjectAnimator.ofFloat(this, "glowAlpha", 1f), 195 ObjectAnimator.ofFloat(this, "glowScale", GLOW_MAX_SCALE_FACTOR) 196 ); 197 as.setDuration(50); 198 } else { 199 as.playTogether( 200 ObjectAnimator.ofFloat(this, "glowAlpha", 0f), 201 ObjectAnimator.ofFloat(this, "glowScale", 1f), 202 ObjectAnimator.ofFloat(this, "drawingAlpha", 0.5f) 203 ); 204 as.setDuration(500); 205 } 206 as.start(); 207 } 208 } 209 super.setPressed(pressed); 210 } 211 212 public boolean onTouchEvent(MotionEvent ev) { 213 final int action = ev.getAction(); 214 int x, y; 215 216 switch (action) { 217 case MotionEvent.ACTION_DOWN: 218 //Slog.d("KeyButtonView", "press"); 219 mDownTime = SystemClock.uptimeMillis(); 220 mRepeat = 0; 221 mSending = true; 222 setPressed(true); 223 sendEvent(KeyEvent.ACTION_DOWN, 224 KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, mDownTime); 225 if (mSupportsLongpress) { 226 removeCallbacks(mCheckLongPress); 227 postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout()); 228 } else { 229 mSending = false; 230 sendEvent(KeyEvent.ACTION_UP, 231 KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, mDownTime); 232 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 233 playSoundEffect(SoundEffectConstants.CLICK); 234 } 235 break; 236 case MotionEvent.ACTION_MOVE: 237 if (mSending) { 238 x = (int)ev.getX(); 239 y = (int)ev.getY(); 240 setPressed(x >= -mTouchSlop 241 && x < getWidth() + mTouchSlop 242 && y >= -mTouchSlop 243 && y < getHeight() + mTouchSlop); 244 } 245 break; 246 case MotionEvent.ACTION_CANCEL: 247 setPressed(false); 248 if (mSending) { 249 mSending = false; 250 sendEvent(KeyEvent.ACTION_UP, 251 KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY 252 | KeyEvent.FLAG_CANCELED); 253 if (mSupportsLongpress) { 254 removeCallbacks(mCheckLongPress); 255 } 256 } 257 break; 258 case MotionEvent.ACTION_UP: 259 final boolean doIt = isPressed(); 260 setPressed(false); 261 if (mSending) { 262 mSending = false; 263 final int flags = KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY; 264 if (mSupportsLongpress) { 265 removeCallbacks(mCheckLongPress); 266 } 267 268 if (mCode != 0) { 269 if (doIt) { 270 sendEvent(KeyEvent.ACTION_UP, flags); 271 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 272 playSoundEffect(SoundEffectConstants.CLICK); 273 } 274 } else { 275 // no key code, just a regular ImageView 276 if (doIt) performClick(); 277 } 278 } 279 break; 280 } 281 282 return true; 283 } 284 285 void sendEvent(int action, int flags) { 286 sendEvent(action, flags, SystemClock.uptimeMillis()); 287 } 288 289 void sendEvent(int action, int flags, long when) { 290 final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, mRepeat, 291 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags, InputDevice.SOURCE_KEYBOARD); 292 try { 293 //Slog.d(TAG, "injecting event " + ev); 294 mWindowManager.injectInputEventNoWait(ev); 295 } catch (RemoteException ex) { 296 // System process is dead 297 } 298 } 299} 300 301 302