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:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user