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;
|
private final AppOpsManager mAppOps;
|
||||||
|
|
||||||
// the platform has no specific capabilities
|
// 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)
|
// 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
|
// 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
|
// the platform type affects volume and silent mode behavior
|
||||||
private final int mPlatformType;
|
private final int mPlatformType;
|
||||||
|
|
||||||
@@ -546,15 +546,7 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
mContentResolver = context.getContentResolver();
|
mContentResolver = context.getContentResolver();
|
||||||
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
|
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
|
||||||
|
|
||||||
if (mContext.getResources().getBoolean(
|
mPlatformType = getPlatformType(context);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
|
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
|
||||||
mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
|
mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
|
||||||
@@ -667,6 +659,26 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
|
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() {
|
public void systemReady() {
|
||||||
sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
|
sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
|
||||||
0, 0, null, 0);
|
0, 0, null, 0);
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ public class MediaSessionLegacyHelper {
|
|||||||
mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
|
mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
|
||||||
direction, flags);
|
direction, flags);
|
||||||
} else if (isMute) {
|
} else if (isMute) {
|
||||||
if (down) {
|
if (down && keyEvent.getRepeatCount() == 0) {
|
||||||
mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
|
mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
|
||||||
AudioManager.ADJUST_TOGGLE_MUTE, flags);
|
AudioManager.ADJUST_TOGGLE_MUTE, flags);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import android.graphics.PixelFormat;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.media.AudioAttributes;
|
import android.media.AudioAttributes;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
import android.media.AudioService;
|
||||||
import android.media.IAudioService;
|
import android.media.IAudioService;
|
||||||
import android.media.Ringtone;
|
import android.media.Ringtone;
|
||||||
import android.media.RingtoneManager;
|
import android.media.RingtoneManager;
|
||||||
@@ -376,6 +377,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
|||||||
int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||||
boolean mHasSoftInput = false;
|
boolean mHasSoftInput = false;
|
||||||
boolean mTranslucentDecorEnabled = true;
|
boolean mTranslucentDecorEnabled = true;
|
||||||
|
boolean mUseTvRouting;
|
||||||
|
boolean mUseMasterVolume;
|
||||||
|
|
||||||
int mPointerLocationMode = 0; // guarded by mLock
|
int mPointerLocationMode = 0; // guarded by mLock
|
||||||
|
|
||||||
@@ -1262,6 +1265,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
|||||||
mTriplePressOnPowerBehavior = mContext.getResources().getInteger(
|
mTriplePressOnPowerBehavior = mContext.getResources().getInteger(
|
||||||
com.android.internal.R.integer.config_triplePressOnPowerBehavior);
|
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();
|
readConfigurationDependentBehaviors();
|
||||||
|
|
||||||
mAccessibilityManager = (AccessibilityManager) context.getSystemService(
|
mAccessibilityManager = (AccessibilityManager) context.getSystemService(
|
||||||
@@ -4534,6 +4541,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
|||||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||||
case KeyEvent.KEYCODE_VOLUME_MUTE: {
|
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 (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
|
||||||
if (down) {
|
if (down) {
|
||||||
if (interactive && !mScreenshotChordVolumeDownKeyTriggered
|
if (interactive && !mScreenshotChordVolumeDownKeyTriggered
|
||||||
@@ -4595,11 +4606,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((result & ACTION_PASS_TO_USER) == 0) {
|
if ((result & ACTION_PASS_TO_USER) == 0) {
|
||||||
|
if (mUseTvRouting) {
|
||||||
|
dispatchDirectAudioEvent(event);
|
||||||
|
} else {
|
||||||
// If we aren't passing to the user and no one else
|
// If we aren't passing to the user and no one else
|
||||||
// handled it send it to the session manager to figure
|
// handled it send it to the session manager to
|
||||||
// out.
|
// figure out.
|
||||||
MediaSessionLegacyHelper.getHelper(mContext)
|
MediaSessionLegacyHelper.getHelper(mContext)
|
||||||
.sendVolumeKeyEvent(event, true);
|
.sendVolumeKeyEvent(event, true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4844,6 +4859,59 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
|||||||
return false;
|
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) {
|
void dispatchMediaKeyWithWakeLock(KeyEvent event) {
|
||||||
if (DEBUG_INPUT) {
|
if (DEBUG_INPUT) {
|
||||||
Slog.d(TAG, "dispatchMediaKeyWithWakeLock: " + event);
|
Slog.d(TAG, "dispatchMediaKeyWithWakeLock: " + event);
|
||||||
|
|||||||
Reference in New Issue
Block a user