KeyButtonView.java revision 5298582717494098fcdf115d832c8e871340d0b5
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    IWindowManager mWindowManager;
53    long mDownTime;
54    boolean mSending;
55    int mCode;
56    int mRepeat;
57    int mTouchSlop;
58    Drawable mGlowBG;
59    float mGlowAlpha = 0f, mGlowScale = 1f, mDrawingAlpha = 1f;
60
61    Runnable mCheckLongPress = new Runnable() {
62        public void run() {
63            if (isPressed()) {
64
65                if (mCode != 0) {
66                    mRepeat++;
67                    sendEvent(KeyEvent.ACTION_DOWN,
68                            KeyEvent.FLAG_FROM_SYSTEM
69                            | KeyEvent.FLAG_VIRTUAL_HARD_KEY
70                            | KeyEvent.FLAG_LONG_PRESS);
71
72                    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
73                } else {
74                    // Just an old-fashioned ImageView
75                    performLongClick();
76                }
77            }
78        }
79    };
80
81    public KeyButtonView(Context context, AttributeSet attrs) {
82        this(context, attrs, 0);
83    }
84
85    public KeyButtonView(Context context, AttributeSet attrs, int defStyle) {
86        super(context, attrs);
87
88        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
89                defStyle, 0);
90
91        mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0);
92
93        mGlowBG = a.getDrawable(R.styleable.KeyButtonView_glowBackground);
94        if (mGlowBG != null) {
95            mDrawingAlpha = 0.5f;
96        }
97
98        a.recycle();
99
100        mWindowManager = IWindowManager.Stub.asInterface(
101                ServiceManager.getService(Context.WINDOW_SERVICE));
102
103        setClickable(true);
104        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
105    }
106
107    @Override
108    protected void onDraw(Canvas canvas) {
109        if (mGlowBG != null) {
110            canvas.save();
111            final int w = getWidth();
112            final int h = getHeight();
113            canvas.scale(mGlowScale, mGlowScale, w*0.5f, h*0.5f);
114            mGlowBG.setBounds(0, 0, w, h);
115            mGlowBG.setAlpha((int)(mGlowAlpha * 255));
116            mGlowBG.draw(canvas);
117            canvas.restore();
118
119            canvas.saveLayerAlpha(null, (int)(mDrawingAlpha * 255), Canvas.ALL_SAVE_FLAG);
120        }
121        super.onDraw(canvas);
122        if (mGlowBG != null) {
123            canvas.restore();
124        }
125    }
126
127    public float getDrawingAlpha() {
128        if (mGlowBG == null) return 0;
129        return mDrawingAlpha;
130    }
131
132    public void setDrawingAlpha(float x) {
133        if (mGlowBG == null) return;
134        mDrawingAlpha = x;
135        invalidate();
136    }
137
138    public float getGlowAlpha() {
139        if (mGlowBG == null) return 0;
140        return mGlowAlpha;
141    }
142
143    public void setGlowAlpha(float x) {
144        if (mGlowBG == null) return;
145        mGlowAlpha = x;
146        invalidate();
147    }
148
149    public float getGlowScale() {
150        if (mGlowBG == null) return 0;
151        return mGlowScale;
152    }
153
154    public void setGlowScale(float x) {
155        if (mGlowBG == null) return;
156        mGlowScale = x;
157        final float w = getWidth();
158        final float h = getHeight();
159        if (x < 1.0f) {
160            invalidate();
161        } else {
162            final float rx = (w * (x - 1.0f)) / 2.0f;
163            final float ry = (h * (x - 1.0f)) / 2.0f;
164            com.android.systemui.SwipeHelper.invalidateGlobalRegion(
165                    this,
166                    new RectF(getLeft() - rx,
167                              getTop() - ry,
168                              getRight() + rx,
169                              getBottom() + ry));
170        }
171    }
172
173    public void setPressed(boolean pressed) {
174        if (mGlowBG != null) {
175            if (pressed != isPressed()) {
176                AnimatorSet as = new AnimatorSet();
177                if (pressed) {
178                    if (mGlowScale < 1.7f) mGlowScale = 1.7f;
179                    if (mGlowAlpha < 0.5f) mGlowAlpha = 0.5f;
180                    setDrawingAlpha(1f);
181                    as.playTogether(
182                        ObjectAnimator.ofFloat(this, "glowAlpha", 1f),
183                        ObjectAnimator.ofFloat(this, "glowScale", 1.8f)
184                    );
185                    as.setDuration(50);
186                } else {
187                    as.playTogether(
188                        ObjectAnimator.ofFloat(this, "glowAlpha", 0f),
189                        ObjectAnimator.ofFloat(this, "glowScale", 1f),
190                        ObjectAnimator.ofFloat(this, "drawingAlpha", 0.5f)
191                    );
192                    as.setDuration(500);
193                }
194                as.start();
195            }
196        }
197        super.setPressed(pressed);
198    }
199
200    public boolean onTouchEvent(MotionEvent ev) {
201        final int action = ev.getAction();
202        int x, y;
203
204        switch (action) {
205            case MotionEvent.ACTION_DOWN:
206                //Slog.d("KeyButtonView", "press");
207                mDownTime = SystemClock.uptimeMillis();
208                mRepeat = 0;
209                mSending = true;
210                sendEvent(KeyEvent.ACTION_DOWN,
211                        KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, mDownTime);
212                setPressed(true);
213                removeCallbacks(mCheckLongPress);
214                postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
215                break;
216            case MotionEvent.ACTION_MOVE:
217                if (mSending) {
218                    x = (int)ev.getX();
219                    y = (int)ev.getY();
220                    setPressed(x >= -mTouchSlop
221                            && x < getWidth() + mTouchSlop
222                            && y >= -mTouchSlop
223                            && y < getHeight() + mTouchSlop);
224                }
225                break;
226            case MotionEvent.ACTION_CANCEL:
227                setPressed(false);
228                if (mSending) {
229                    mSending = false;
230                    sendEvent(KeyEvent.ACTION_UP,
231                            KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY
232                                | KeyEvent.FLAG_CANCELED);
233                    removeCallbacks(mCheckLongPress);
234                }
235                break;
236            case MotionEvent.ACTION_UP:
237                final boolean doIt = isPressed();
238                setPressed(false);
239                if (mSending) {
240                    mSending = false;
241                    final int flags = KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY;
242                    removeCallbacks(mCheckLongPress);
243
244                    if (mCode != 0) {
245                        if (doIt) {
246                            sendEvent(KeyEvent.ACTION_UP, flags);
247                            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
248                            playSoundEffect(SoundEffectConstants.CLICK);
249                        } else {
250                            sendEvent(KeyEvent.ACTION_UP, flags | KeyEvent.FLAG_CANCELED);
251                        }
252                    } else {
253                        // no key code, just a regular ImageView
254                        if (doIt) performClick();
255                    }
256                }
257                break;
258        }
259
260        return true;
261    }
262
263    void sendEvent(int action, int flags) {
264        sendEvent(action, flags, SystemClock.uptimeMillis());
265    }
266
267    void sendEvent(int action, int flags, long when) {
268        final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, mRepeat,
269                0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, flags, InputDevice.SOURCE_KEYBOARD);
270        try {
271            //Slog.d(TAG, "injecting event " + ev);
272            mWindowManager.injectInputEventNoWait(ev);
273        } catch (RemoteException ex) {
274            // System process is dead
275        }
276    }
277}
278
279
280