Route volume keys directly to the audio system on TVs

This routes volume and mute keys directly to the audio system when
on a television instead of letting apps or sessions intercept them.

Change-Id: I2af47e30c7842aca96d045a6cc9ca025b94e546a
This commit is contained in:
RoboErik
2015-01-26 15:53:51 -08:00
parent 4197cb60bc
commit 001c59c637
3 changed files with 98 additions and 18 deletions

View File

@@ -153,11 +153,11 @@ public class AudioService extends IAudioService.Stub {
private final AppOpsManager mAppOps;
// the platform has no specific capabilities
private static final int PLATFORM_DEFAULT = 0;
public static final int PLATFORM_DEFAULT = 0;
// the platform is voice call capable (a phone)
private static final int PLATFORM_VOICE = 1;
public static final int PLATFORM_VOICE = 1;
// the platform is a television or a set-top box
private static final int PLATFORM_TELEVISION = 2;
public static final int PLATFORM_TELEVISION = 2;
// the platform type affects volume and silent mode behavior
private final int mPlatformType;
@@ -546,15 +546,7 @@ public class AudioService extends IAudioService.Stub {
mContentResolver = context.getContentResolver();
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
if (mContext.getResources().getBoolean(
com.android.internal.R.bool.config_voice_capable)) {
mPlatformType = PLATFORM_VOICE;
} else if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LEANBACK)) {
mPlatformType = PLATFORM_TELEVISION;
} else {
mPlatformType = PLATFORM_DEFAULT;
}
mPlatformType = getPlatformType(context);
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
@@ -667,6 +659,26 @@ public class AudioService extends IAudioService.Stub {
LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
}
/**
* Return the platform type that this is running on. One of:
* <ul>
* <li>{@link #PLATFORM_VOICE}</li>
* <li>{@link #PLATFORM_TELEVISION}</li>
* <li>{@link #PLATFORM_DEFAULT}</li>
* </ul>
*/
public static int getPlatformType(Context context) {
if (context.getResources().getBoolean(
com.android.internal.R.bool.config_voice_capable)) {
return PLATFORM_VOICE;
} else if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LEANBACK)) {
return PLATFORM_TELEVISION;
} else {
return PLATFORM_DEFAULT;
}
}
public void systemReady() {
sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
0, 0, null, 0);

View File

@@ -221,7 +221,7 @@ public class MediaSessionLegacyHelper {
mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
direction, flags);
} else if (isMute) {
if (down) {
if (down && keyEvent.getRepeatCount() == 0) {
mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
AudioManager.ADJUST_TOGGLE_MUTE, flags);
}

View File

@@ -43,6 +43,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioService;
import android.media.IAudioService;
import android.media.Ringtone;
import android.media.RingtoneManager;
@@ -376,6 +377,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
boolean mHasSoftInput = false;
boolean mTranslucentDecorEnabled = true;
boolean mUseTvRouting;
boolean mUseMasterVolume;
int mPointerLocationMode = 0; // guarded by mLock
@@ -1262,6 +1265,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mTriplePressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_triplePressOnPowerBehavior);
mUseTvRouting = AudioService.getPlatformType(mContext) == AudioService.PLATFORM_TELEVISION;
mUseMasterVolume = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_useMasterVolume);
readConfigurationDependentBehaviors();
mAccessibilityManager = (AccessibilityManager) context.getSystemService(
@@ -4534,6 +4541,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (mUseTvRouting) {
// On TVs volume keys never go to the foreground app
result &= ~ACTION_PASS_TO_USER;
}
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
if (down) {
if (interactive && !mScreenshotChordVolumeDownKeyTriggered
@@ -4595,11 +4606,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if ((result & ACTION_PASS_TO_USER) == 0) {
// If we aren't passing to the user and no one else
// handled it send it to the session manager to figure
// out.
MediaSessionLegacyHelper.getHelper(mContext)
.sendVolumeKeyEvent(event, true);
if (mUseTvRouting) {
dispatchDirectAudioEvent(event);
} else {
// If we aren't passing to the user and no one else
// handled it send it to the session manager to
// figure out.
MediaSessionLegacyHelper.getHelper(mContext)
.sendVolumeKeyEvent(event, true);
}
break;
}
}
@@ -4844,6 +4859,59 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return false;
}
private void dispatchDirectAudioEvent(KeyEvent event) {
if (event.getAction() != KeyEvent.ACTION_DOWN) {
return;
}
int keyCode = event.getKeyCode();
int flags = AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_PLAY_SOUND;
String pkgName = mContext.getOpPackageName();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
try {
if (mUseMasterVolume) {
getAudioService().adjustMasterVolume(AudioManager.ADJUST_RAISE, flags,
pkgName);
} else {
getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
}
} catch (RemoteException e) {
Log.e(TAG, "Error dispatching volume up in dispatchTvAudioEvent.", e);
}
break;
case KeyEvent.KEYCODE_VOLUME_DOWN:
try {
if (mUseMasterVolume) {
getAudioService().adjustMasterVolume(AudioManager.ADJUST_LOWER, flags,
pkgName);
} else {
getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
}
} catch (RemoteException e) {
Log.e(TAG, "Error dispatching volume down in dispatchTvAudioEvent.", e);
}
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
try {
if (event.getRepeatCount() == 0) {
if (mUseMasterVolume) {
getAudioService().adjustMasterVolume(AudioManager.ADJUST_TOGGLE_MUTE,
flags, pkgName);
} else {
getAudioService().adjustSuggestedStreamVolume(
AudioManager.ADJUST_TOGGLE_MUTE,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
}
}
} catch (RemoteException e) {
Log.e(TAG, "Error dispatching mute in dispatchTvAudioEvent.", e);
}
break;
}
}
void dispatchMediaKeyWithWakeLock(KeyEvent event) {
if (DEBUG_INPUT) {
Slog.d(TAG, "dispatchMediaKeyWithWakeLock: " + event);