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