KeyguardViewBase.java revision dcb3d84b82cc2448d04e73359a716581bfb657db
1/*
2 * Copyright (C) 2007 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.internal.policy.impl.keyguard;
18
19import android.content.Context;
20import android.graphics.Canvas;
21import android.graphics.ColorFilter;
22import android.graphics.PixelFormat;
23import android.graphics.PorterDuff;
24import android.graphics.drawable.Drawable;
25import android.media.AudioManager;
26import android.media.IAudioService;
27import android.os.RemoteException;
28import android.os.ServiceManager;
29import android.telephony.TelephonyManager;
30import android.view.KeyEvent;
31import android.widget.LinearLayout;
32import android.util.AttributeSet;
33import android.util.Log;
34import android.util.Slog;
35
36/**
37 * Base class for keyguard view.  {@link #reset} is where you should
38 * reset the state of your view.  Use the {@link KeyguardViewCallback} via
39 * {@link #getCallback()} to send information back (such as poking the wake lock,
40 * or finishing the keyguard).
41 *
42 * Handles intercepting of media keys that still work when the keyguard is
43 * showing.
44 */
45public abstract class KeyguardViewBase extends LinearLayout {
46
47    private static final int BACKGROUND_COLOR = 0x70000000;
48    private AudioManager mAudioManager;
49    private TelephonyManager mTelephonyManager = null;
50    protected KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
51
52    // Whether the volume keys should be handled by keyguard. If true, then
53    // they will be handled here for specific media types such as music, otherwise
54    // the audio service will bring up the volume dialog.
55    private static final boolean KEYGUARD_MANAGES_VOLUME = true;
56
57    // This is a faster way to draw the background on devices without hardware acceleration
58    private static final Drawable mBackgroundDrawable = new Drawable() {
59        @Override
60        public void draw(Canvas canvas) {
61            canvas.drawColor(BACKGROUND_COLOR, PorterDuff.Mode.SRC);
62        }
63
64        @Override
65        public void setAlpha(int alpha) {
66        }
67
68        @Override
69        public void setColorFilter(ColorFilter cf) {
70        }
71
72        @Override
73        public int getOpacity() {
74            return PixelFormat.TRANSLUCENT;
75        }
76    };
77
78    public KeyguardViewBase(Context context) {
79        this(context, null);
80    }
81
82    public KeyguardViewBase(Context context, AttributeSet attrs) {
83        super(context, attrs);
84        resetBackground();
85    }
86
87    public void resetBackground() {
88        setBackground(mBackgroundDrawable);
89    }
90
91    /**
92     * Called when you need to reset the state of your view.
93     */
94    abstract public void reset();
95
96    /**
97     * Called when the screen turned off.
98     */
99    abstract public void onScreenTurnedOff();
100
101    /**
102     * Called when the screen turned on.
103     */
104    abstract public void onScreenTurnedOn();
105
106    /**
107     * Called when the view needs to be shown.
108     */
109    abstract public void show();
110
111    /**
112     * Called when a key has woken the device to give us a chance to adjust our
113     * state according the the key.  We are responsible for waking the device
114     * (by poking the wake lock) once we are ready.
115     *
116     * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}.
117     * Be sure not to take any action that takes a long time; any significant
118     * action should be posted to a handler.
119     *
120     * @param keyCode The wake key, which may be relevant for configuring the
121     *   keyguard.  May be {@link KeyEvent#KEYCODE_UNKNOWN} if waking for a reason
122     *   other than a key press.
123     */
124    abstract public void wakeWhenReadyTq(int keyCode);
125
126    /**
127     * Verify that the user can get past the keyguard securely.  This is called,
128     * for example, when the phone disables the keyguard but then wants to launch
129     * something else that requires secure access.
130     *
131     * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)}
132     */
133    abstract public void verifyUnlock();
134
135    /**
136     * Called before this view is being removed.
137     */
138    abstract public void cleanUp();
139
140    @Override
141    public boolean dispatchKeyEvent(KeyEvent event) {
142        if (interceptMediaKey(event)) {
143            return true;
144        }
145        return super.dispatchKeyEvent(event);
146    }
147
148    /**
149     * Allows the media keys to work when the keyguard is showing.
150     * The media keys should be of no interest to the actual keyguard view(s),
151     * so intercepting them here should not be of any harm.
152     * @param event The key event
153     * @return whether the event was consumed as a media key.
154     */
155    private boolean interceptMediaKey(KeyEvent event) {
156        final int keyCode = event.getKeyCode();
157        if (event.getAction() == KeyEvent.ACTION_DOWN) {
158            switch (keyCode) {
159                case KeyEvent.KEYCODE_MEDIA_PLAY:
160                case KeyEvent.KEYCODE_MEDIA_PAUSE:
161                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
162                    /* Suppress PLAY/PAUSE toggle when phone is ringing or
163                     * in-call to avoid music playback */
164                    if (mTelephonyManager == null) {
165                        mTelephonyManager = (TelephonyManager) getContext().getSystemService(
166                                Context.TELEPHONY_SERVICE);
167                    }
168                    if (mTelephonyManager != null &&
169                            mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
170                        return true;  // suppress key event
171                    }
172                case KeyEvent.KEYCODE_MUTE:
173                case KeyEvent.KEYCODE_HEADSETHOOK:
174                case KeyEvent.KEYCODE_MEDIA_STOP:
175                case KeyEvent.KEYCODE_MEDIA_NEXT:
176                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
177                case KeyEvent.KEYCODE_MEDIA_REWIND:
178                case KeyEvent.KEYCODE_MEDIA_RECORD:
179                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
180                    handleMediaKeyEvent(event);
181                    return true;
182                }
183
184                case KeyEvent.KEYCODE_VOLUME_UP:
185                case KeyEvent.KEYCODE_VOLUME_DOWN:
186                case KeyEvent.KEYCODE_VOLUME_MUTE: {
187                    if (KEYGUARD_MANAGES_VOLUME) {
188                        synchronized (this) {
189                            if (mAudioManager == null) {
190                                mAudioManager = (AudioManager) getContext().getSystemService(
191                                        Context.AUDIO_SERVICE);
192                            }
193                        }
194                        // Volume buttons should only function for music (local or remote).
195                        // TODO: Actually handle MUTE.
196                        mAudioManager.adjustLocalOrRemoteStreamVolume(
197                                AudioManager.STREAM_MUSIC,
198                                keyCode == KeyEvent.KEYCODE_VOLUME_UP
199                                        ? AudioManager.ADJUST_RAISE
200                                        : AudioManager.ADJUST_LOWER);
201                        // Don't execute default volume behavior
202                        return true;
203                    } else {
204                        return false;
205                    }
206                }
207            }
208        } else if (event.getAction() == KeyEvent.ACTION_UP) {
209            switch (keyCode) {
210                case KeyEvent.KEYCODE_MUTE:
211                case KeyEvent.KEYCODE_HEADSETHOOK:
212                case KeyEvent.KEYCODE_MEDIA_PLAY:
213                case KeyEvent.KEYCODE_MEDIA_PAUSE:
214                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
215                case KeyEvent.KEYCODE_MEDIA_STOP:
216                case KeyEvent.KEYCODE_MEDIA_NEXT:
217                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
218                case KeyEvent.KEYCODE_MEDIA_REWIND:
219                case KeyEvent.KEYCODE_MEDIA_RECORD:
220                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
221                    handleMediaKeyEvent(event);
222                    return true;
223                }
224            }
225        }
226        return false;
227    }
228
229    void handleMediaKeyEvent(KeyEvent keyEvent) {
230        IAudioService audioService = IAudioService.Stub.asInterface(
231                ServiceManager.checkService(Context.AUDIO_SERVICE));
232        if (audioService != null) {
233            try {
234                audioService.dispatchMediaKeyEvent(keyEvent);
235            } catch (RemoteException e) {
236                Log.e("KeyguardViewBase", "dispatchMediaKeyEvent threw exception " + e);
237            }
238        } else {
239            Slog.w("KeyguardViewBase", "Unable to find IAudioService for media key event");
240        }
241    }
242
243    @Override
244    public void dispatchSystemUiVisibilityChanged(int visibility) {
245        super.dispatchSystemUiVisibilityChanged(visibility);
246        setSystemUiVisibility(STATUS_BAR_DISABLE_BACK);
247    }
248
249    public void setViewMediatorCallback(
250            KeyguardViewMediator.ViewMediatorCallback viewMediatorCallback) {
251        mViewMediatorCallback = viewMediatorCallback;
252    }
253
254}
255