diff options
author | RoboErik <epastern@google.com> | 2014-05-20 14:53:39 -0700 |
---|---|---|
committer | RoboErik <epastern@google.com> | 2014-05-20 14:57:46 -0700 |
commit | 9a9d0b5f6f4be758ed6c8b837a9dd01a451bc0c0 (patch) | |
tree | 5bf1b7009e161cb10b2a88c76c5848814dcaf276 /services/core/java/com/android/server/media | |
parent | 418c10ca9df1505509afeffd558cd92fc97bc635 (diff) | |
download | frameworks_base-9a9d0b5f6f4be758ed6c8b837a9dd01a451bc0c0.zip frameworks_base-9a9d0b5f6f4be758ed6c8b837a9dd01a451bc0c0.tar.gz frameworks_base-9a9d0b5f6f4be758ed6c8b837a9dd01a451bc0c0.tar.bz2 |
Handle headsethook voice launching
This launches voice search when headsethook is long pressed unless
you're in a call. The handling is done in MediaSessionService. This
CL also adds a switch to the new APIs to the fallback event handler
which was missed previously.
Change-Id: I1cbdff1d6e9f5293885dd8aaed8ba13cb15b36d4
Diffstat (limited to 'services/core/java/com/android/server/media')
-rw-r--r-- | services/core/java/com/android/server/media/MediaSessionService.java | 146 |
1 files changed, 118 insertions, 28 deletions
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 9a1c6d5..9d85167 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -19,6 +19,8 @@ package com.android.server.media; import android.Manifest; import android.app.Activity; import android.app.ActivityManager; +import android.app.KeyguardManager; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -40,6 +42,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.UserHandle; import android.provider.Settings; +import android.speech.RecognizerIntent; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; @@ -75,6 +78,8 @@ public class MediaSessionService extends SystemService implements Monitor { private final Handler mHandler = new Handler(); private final PowerManager.WakeLock mMediaEventWakeLock; + private KeyguardManager mKeyguardManager; + private MediaSessionRecord mPrioritySession; private int mCurrentUserId = -1; @@ -98,6 +103,8 @@ public class MediaSessionService extends SystemService implements Monitor { publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl); Watchdog.getInstance().addMonitor(this); updateUser(); + mKeyguardManager = + (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE); } /** @@ -601,6 +608,9 @@ public class MediaSessionService extends SystemService implements Monitor { "android.media.AudioService.WAKELOCK_ACQUIRED"; private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number + private boolean mVoiceButtonDown = false; + private boolean mVoiceButtonHandled = false; + @Override public ISession createSession(String packageName, ISessionCallback cb, String tag, int userId) throws RemoteException { @@ -679,36 +689,12 @@ public class MediaSessionService extends SystemService implements Monitor { try { synchronized (mLock) { - MediaSessionRecord mbSession = mPriorityStack + MediaSessionRecord session = mPriorityStack .getDefaultMediaButtonSession(mCurrentUserId); - if (mbSession != null) { - if (DEBUG) { - Log.d(TAG, "Sending media key to " + mbSession.getSessionInfo()); - } - if (needWakeLock) { - mKeyEventReceiver.aquireWakeLockLocked(); - } - // If we don't need a wakelock use -1 as the id so we - // won't release it later - mbSession.sendMediaButton(keyEvent, - needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1, - mKeyEventReceiver); + if (isVoiceKey(keyEvent.getKeyCode())) { + handleVoiceKeyEventLocked(keyEvent, needWakeLock, session); } else { - if (needWakeLock) { - mMediaEventWakeLock.acquire(); - } - if (DEBUG) { - Log.d(TAG, "Sending media key ordered broadcast"); - } - // Fallback to legacy behavior - Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); - keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); - if (needWakeLock) { - keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, - WAKELOCK_RELEASE_ON_FINISHED); - } - getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL, - null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null); + dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session); } } } finally { @@ -751,6 +737,110 @@ public class MediaSessionService extends SystemService implements Monitor { } } + private void handleVoiceKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock, + MediaSessionRecord session) { + if (session != null && session.hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) { + // If the phone app has priority just give it the event + dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session); + return; + } + int action = keyEvent.getAction(); + boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0; + if (action == KeyEvent.ACTION_DOWN) { + if (keyEvent.getRepeatCount() == 0) { + mVoiceButtonDown = true; + mVoiceButtonHandled = false; + } else if (mVoiceButtonDown && !mVoiceButtonHandled && isLongPress) { + mVoiceButtonHandled = true; + startVoiceInput(needWakeLock); + } + } else if (action == KeyEvent.ACTION_UP) { + if (mVoiceButtonDown) { + mVoiceButtonDown = false; + if (!mVoiceButtonHandled && !keyEvent.isCanceled()) { + // Resend the down then send this event through + KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN); + dispatchMediaKeyEventLocked(downEvent, needWakeLock, session); + dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session); + } + } + } + } + + private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock, + MediaSessionRecord session) { + if (session != null) { + if (DEBUG) { + Log.d(TAG, "Sending media key to " + session.getSessionInfo()); + } + if (needWakeLock) { + mKeyEventReceiver.aquireWakeLockLocked(); + } + // If we don't need a wakelock use -1 as the id so we + // won't release it later + session.sendMediaButton(keyEvent, + needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1, + mKeyEventReceiver); + } else { + if (needWakeLock) { + mMediaEventWakeLock.acquire(); + } + if (DEBUG) { + Log.d(TAG, "Sending media key ordered broadcast"); + } + // Fallback to legacy behavior + Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + if (needWakeLock) { + keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, + WAKELOCK_RELEASE_ON_FINISHED); + } + getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL, + null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null); + } + } + + private void startVoiceInput(boolean needWakeLock) { + Intent voiceIntent = null; + // select which type of search to launch: + // - screen on and device unlocked: action is ACTION_WEB_SEARCH + // - device locked or screen off: action is + // ACTION_VOICE_SEARCH_HANDS_FREE + // with EXTRA_SECURE set to true if the device is securely locked + PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); + boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); + if (!isLocked && pm.isScreenOn()) { + voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH); + Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH"); + } else { + voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); + voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, + isLocked && mKeyguardManager.isKeyguardSecure()); + Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE"); + } + // start the search activity + if (needWakeLock) { + mMediaEventWakeLock.acquire(); + } + try { + if (voiceIntent != null) { + voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + getContext().startActivityAsUser(voiceIntent, UserHandle.CURRENT); + } + } catch (ActivityNotFoundException e) { + Log.w(TAG, "No activity for search: " + e); + } finally { + if (needWakeLock) { + mMediaEventWakeLock.release(); + } + } + } + + private boolean isVoiceKey(int keyCode) { + return keyCode == KeyEvent.KEYCODE_HEADSETHOOK; + } + private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler); class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable { |