Home | History | Annotate | Download | only in keyguard
      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 
     17 package com.android.keyguard;
     18 
     19 import android.app.Activity;
     20 import android.content.Context;
     21 import android.media.AudioManager;
     22 import android.media.IAudioService;
     23 import android.os.RemoteException;
     24 import android.os.ServiceManager;
     25 import android.telephony.TelephonyManager;
     26 import android.util.AttributeSet;
     27 import android.util.Log;
     28 import android.util.Slog;
     29 import android.view.KeyEvent;
     30 import android.widget.FrameLayout;
     31 
     32 /**
     33  * Base class for keyguard view.  {@link #reset} is where you should
     34  * reset the state of your view.  Use the {@link KeyguardViewCallback} via
     35  * {@link #getCallback()} to send information back (such as poking the wake lock,
     36  * or finishing the keyguard).
     37  *
     38  * Handles intercepting of media keys that still work when the keyguard is
     39  * showing.
     40  */
     41 public abstract class KeyguardViewBase extends FrameLayout {
     42 
     43     private AudioManager mAudioManager;
     44     private TelephonyManager mTelephonyManager = null;
     45     protected KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
     46 
     47     // Whether the volume keys should be handled by keyguard. If true, then
     48     // they will be handled here for specific media types such as music, otherwise
     49     // the audio service will bring up the volume dialog.
     50     private static final boolean KEYGUARD_MANAGES_VOLUME = true;
     51 
     52     public KeyguardViewBase(Context context) {
     53         this(context, null);
     54     }
     55 
     56     public KeyguardViewBase(Context context, AttributeSet attrs) {
     57         super(context, attrs);
     58     }
     59 
     60     /**
     61      * Called when the screen turned off.
     62      */
     63     abstract public void onScreenTurnedOff();
     64 
     65     /**
     66      * Called when the screen turned on.
     67      */
     68     abstract public void onScreenTurnedOn();
     69 
     70     /**
     71      * Called when the view needs to be shown.
     72      */
     73     abstract public void show();
     74 
     75     /**
     76      * Verify that the user can get past the keyguard securely.  This is called,
     77      * for example, when the phone disables the keyguard but then wants to launch
     78      * something else that requires secure access.
     79      *
     80      * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)}
     81      */
     82     abstract public void verifyUnlock();
     83 
     84     /**
     85      * Called before this view is being removed.
     86      */
     87     abstract public void cleanUp();
     88 
     89     /**
     90      * Gets the desired user activity timeout in milliseconds, or -1 if the
     91      * default should be used.
     92      */
     93     abstract public long getUserActivityTimeout();
     94 
     95     @Override
     96     public boolean dispatchKeyEvent(KeyEvent event) {
     97         if (interceptMediaKey(event)) {
     98             return true;
     99         }
    100         return super.dispatchKeyEvent(event);
    101     }
    102 
    103     /**
    104      * Allows the media keys to work when the keyguard is showing.
    105      * The media keys should be of no interest to the actual keyguard view(s),
    106      * so intercepting them here should not be of any harm.
    107      * @param event The key event
    108      * @return whether the event was consumed as a media key.
    109      */
    110     private boolean interceptMediaKey(KeyEvent event) {
    111         final int keyCode = event.getKeyCode();
    112         if (event.getAction() == KeyEvent.ACTION_DOWN) {
    113             switch (keyCode) {
    114                 case KeyEvent.KEYCODE_MEDIA_PLAY:
    115                 case KeyEvent.KEYCODE_MEDIA_PAUSE:
    116                 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
    117                     /* Suppress PLAY/PAUSE toggle when phone is ringing or
    118                      * in-call to avoid music playback */
    119                     if (mTelephonyManager == null) {
    120                         mTelephonyManager = (TelephonyManager) getContext().getSystemService(
    121                                 Context.TELEPHONY_SERVICE);
    122                     }
    123                     if (mTelephonyManager != null &&
    124                             mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
    125                         return true;  // suppress key event
    126                     }
    127                 case KeyEvent.KEYCODE_MUTE:
    128                 case KeyEvent.KEYCODE_HEADSETHOOK:
    129                 case KeyEvent.KEYCODE_MEDIA_STOP:
    130                 case KeyEvent.KEYCODE_MEDIA_NEXT:
    131                 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
    132                 case KeyEvent.KEYCODE_MEDIA_REWIND:
    133                 case KeyEvent.KEYCODE_MEDIA_RECORD:
    134                 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
    135                 case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
    136                     handleMediaKeyEvent(event);
    137                     return true;
    138                 }
    139 
    140                 case KeyEvent.KEYCODE_VOLUME_UP:
    141                 case KeyEvent.KEYCODE_VOLUME_DOWN:
    142                 case KeyEvent.KEYCODE_VOLUME_MUTE: {
    143                     if (KEYGUARD_MANAGES_VOLUME) {
    144                         synchronized (this) {
    145                             if (mAudioManager == null) {
    146                                 mAudioManager = (AudioManager) getContext().getSystemService(
    147                                         Context.AUDIO_SERVICE);
    148                             }
    149                         }
    150                         // Volume buttons should only function for music (local or remote).
    151                         // TODO: Actually handle MUTE.
    152                         mAudioManager.adjustLocalOrRemoteStreamVolume(
    153                                 AudioManager.STREAM_MUSIC,
    154                                 keyCode == KeyEvent.KEYCODE_VOLUME_UP
    155                                         ? AudioManager.ADJUST_RAISE
    156                                         : AudioManager.ADJUST_LOWER);
    157                         // Don't execute default volume behavior
    158                         return true;
    159                     } else {
    160                         return false;
    161                     }
    162                 }
    163             }
    164         } else if (event.getAction() == KeyEvent.ACTION_UP) {
    165             switch (keyCode) {
    166                 case KeyEvent.KEYCODE_MUTE:
    167                 case KeyEvent.KEYCODE_HEADSETHOOK:
    168                 case KeyEvent.KEYCODE_MEDIA_PLAY:
    169                 case KeyEvent.KEYCODE_MEDIA_PAUSE:
    170                 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
    171                 case KeyEvent.KEYCODE_MEDIA_STOP:
    172                 case KeyEvent.KEYCODE_MEDIA_NEXT:
    173                 case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
    174                 case KeyEvent.KEYCODE_MEDIA_REWIND:
    175                 case KeyEvent.KEYCODE_MEDIA_RECORD:
    176                 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
    177                 case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
    178                     handleMediaKeyEvent(event);
    179                     return true;
    180                 }
    181             }
    182         }
    183         return false;
    184     }
    185 
    186     void handleMediaKeyEvent(KeyEvent keyEvent) {
    187         IAudioService audioService = IAudioService.Stub.asInterface(
    188                 ServiceManager.checkService(Context.AUDIO_SERVICE));
    189         if (audioService != null) {
    190             try {
    191                 audioService.dispatchMediaKeyEvent(keyEvent);
    192             } catch (RemoteException e) {
    193                 Log.e("KeyguardViewBase", "dispatchMediaKeyEvent threw exception " + e);
    194             }
    195         } else {
    196             Slog.w("KeyguardViewBase", "Unable to find IAudioService for media key event");
    197         }
    198     }
    199 
    200     @Override
    201     public void dispatchSystemUiVisibilityChanged(int visibility) {
    202         super.dispatchSystemUiVisibilityChanged(visibility);
    203 
    204         if (!(mContext instanceof Activity)) {
    205             setSystemUiVisibility(STATUS_BAR_DISABLE_BACK);
    206         }
    207     }
    208 
    209     public void setViewMediatorCallback(
    210             KeyguardViewMediator.ViewMediatorCallback viewMediatorCallback) {
    211         mViewMediatorCallback = viewMediatorCallback;
    212     }
    213 }
    214