diff options
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | media/java/android/media/AudioManager.java | 78 | ||||
-rw-r--r-- | media/java/android/media/AudioService.java | 71 | ||||
-rw-r--r-- | media/java/android/media/IAudioService.aidl | 7 | ||||
-rw-r--r-- | media/java/android/media/IVolumeController.aidl | 42 | ||||
-rw-r--r-- | media/java/android/media/VolumeController.java | 118 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/SystemUIApplication.java | 1 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java (renamed from core/java/android/view/VolumePanel.java) | 56 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java | 125 |
9 files changed, 449 insertions, 50 deletions
@@ -306,6 +306,7 @@ LOCAL_SRC_FILES += \ media/java/android/media/IRemoteDisplayProvider.aidl \ media/java/android/media/IRemoteVolumeObserver.aidl \ media/java/android/media/IRingtonePlayer.aidl \ + media/java/android/media/IVolumeController.aidl \ media/java/android/media/routeprovider/IRouteConnection.aidl \ media/java/android/media/routeprovider/IRouteProvider.aidl \ media/java/android/media/routeprovider/IRouteProviderCallback.aidl \ diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 575667d..9803161 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -37,7 +37,6 @@ import android.os.ServiceManager; import android.provider.Settings; import android.util.Log; import android.view.KeyEvent; -import android.view.VolumePanel; import java.util.HashMap; @@ -498,7 +497,7 @@ public class AudioManager { int keyCode = event.getKeyCode(); if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE - && mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY + && mVolumeKeyUpTime + AudioService.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) { /* * The user has hit another key during the delay (e.g., 300ms) @@ -2892,4 +2891,79 @@ public class AudioManager { return AudioSystem.getOutputLatency(streamType); } + /** + * Registers a global volume controller interface. Currently limited to SystemUI. + * + * @hide + */ + public void setVolumeController(IVolumeController controller) { + try { + getService().setVolumeController(controller); + } catch (RemoteException e) { + Log.w(TAG, "Error setting volume controller", e); + } + } + + /** + * Only useful for volume controllers. + * @hide + */ + public int getRemoteStreamVolume() { + try { + return getService().getRemoteStreamVolume(); + } catch (RemoteException e) { + Log.w(TAG, "Error getting remote stream volume", e); + return 0; + } + } + + /** + * Only useful for volume controllers. + * @hide + */ + public int getRemoteStreamMaxVolume() { + try { + return getService().getRemoteStreamMaxVolume(); + } catch (RemoteException e) { + Log.w(TAG, "Error getting remote stream max volume", e); + return 0; + } + } + + /** + * Only useful for volume controllers. + * @hide + */ + public void setRemoteStreamVolume(int index) { + try { + getService().setRemoteStreamVolume(index); + } catch (RemoteException e) { + Log.w(TAG, "Error setting remote stream volume", e); + } + } + + /** + * Only useful for volume controllers. + * @hide + */ + public boolean isStreamAffectedByRingerMode(int streamType) { + try { + return getService().isStreamAffectedByRingerMode(streamType); + } catch (RemoteException e) { + Log.w(TAG, "Error calling isStreamAffectedByRingerMode", e); + return false; + } + } + + /** + * Only useful for volume controllers. + * @hide + */ + public void disableSafeMediaVolume() { + try { + getService().disableSafeMediaVolume(); + } catch (RemoteException e) { + Log.w(TAG, "Error disabling safe media volume", e); + } + } } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 6e623a5..c736fc7 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -67,7 +67,6 @@ import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.Surface; -import android.view.VolumePanel; import android.view.WindowManager; import com.android.internal.telephony.ITelephony; @@ -116,13 +115,21 @@ public class AudioService extends IAudioService.Stub { /** How long to delay before persisting a change in volume/ringer mode. */ private static final int PERSIST_DELAY = 500; + /** + * The delay before playing a sound. This small period exists so the user + * can press another key (non-volume keys, too) to have it NOT be audible. + * <p> + * PhoneWindow will implement this part. + */ + public static final int PLAY_SOUND_DELAY = 300; + private final Context mContext; private final ContentResolver mContentResolver; private final AppOpsManager mAppOps; private final boolean mVoiceCapable; - /** The UI */ - private VolumePanel mVolumePanel; + /** The controller for the volume UI. */ + private final VolumeController mVolumeController = new VolumeController(); // sendMsg() flags /** If the msg is already queued, replace it with this one. */ @@ -477,13 +484,12 @@ public class AudioService extends IAudioService.Stub { sSoundEffectVolumeDb = context.getResources().getInteger( com.android.internal.R.integer.config_soundEffectVolumeDb); - mVolumePanel = new VolumePanel(context, this); mForcedUseForComm = AudioSystem.FORCE_NONE; createAudioSystemThread(); mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(), - mContext, /*VolumeController*/ mVolumePanel, this); + mContext, mVolumeController, this); AudioSystem.setErrorCallback(mAudioSystemCallback); @@ -953,7 +959,7 @@ public class AudioService extends IAudioService.Stub { if ((direction == AudioManager.ADJUST_RAISE) && !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex); - mVolumePanel.postDisplaySafeVolumeWarning(flags); + mVolumeController.postDisplaySafeVolumeWarning(flags); } else if (streamState.adjustIndex(direction * step, device)) { // Post message to set system volume (it in turn will post a message // to persist). Do not change volume if stream is muted. @@ -1081,7 +1087,7 @@ public class AudioService extends IAudioService.Stub { } if (!checkSafeMediaVolume(streamTypeAlias, index, device)) { - mVolumePanel.postDisplaySafeVolumeWarning(flags); + mVolumeController.postDisplaySafeVolumeWarning(flags); mPendingVolumeCommand = new StreamVolumeCommand( streamType, index, flags, device); } else { @@ -1202,7 +1208,7 @@ public class AudioService extends IAudioService.Stub { streamType = AudioSystem.STREAM_NOTIFICATION; } - mVolumePanel.postVolumeChanged(streamType, flags); + mVolumeController.postVolumeChanged(streamType, flags); if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) { oldIndex = (oldIndex + 5) / 10; @@ -1217,7 +1223,7 @@ public class AudioService extends IAudioService.Stub { // UI update and Broadcast Intent private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) { - mVolumePanel.postMasterVolumeChanged(flags); + mVolumeController.postMasterVolumeChanged(flags); Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION); intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume); @@ -1227,7 +1233,7 @@ public class AudioService extends IAudioService.Stub { // UI update and Broadcast Intent private void sendMasterMuteUpdate(boolean muted, int flags) { - mVolumePanel.postMasterMuteChanged(flags); + mVolumeController.postMasterMuteChanged(flags); broadcastMasterMuteStatus(muted); } @@ -2589,6 +2595,7 @@ public class AudioService extends IAudioService.Stub { return adjustVolumeIndex; } + @Override public boolean isStreamAffectedByRingerMode(int streamType) { return (mRingerModeAffectedStreams & (1 << streamType)) != 0; } @@ -4309,15 +4316,19 @@ public class AudioService extends IAudioService.Stub { mMediaFocusControl.registerRemoteVolumeObserverForRcc(rccId, rvo); } + @Override public int getRemoteStreamVolume() { return mMediaFocusControl.getRemoteStreamVolume(); } + @Override public int getRemoteStreamMaxVolume() { return mMediaFocusControl.getRemoteStreamMaxVolume(); } + @Override public void setRemoteStreamVolume(int index) { + enforceSelfOrSystemUI("set the remote stream volume"); mMediaFocusControl.setRemoteStreamVolume(index); } @@ -4450,7 +4461,7 @@ public class AudioService extends IAudioService.Stub { } } } - mVolumePanel.setLayoutDirection(config.getLayoutDirection()); + mVolumeController.setLayoutDirection(config.getLayoutDirection()); } catch (Exception e) { Log.e(TAG, "Error handling configuration change: ", e); } @@ -4625,7 +4636,9 @@ public class AudioService extends IAudioService.Stub { } } + @Override public void disableSafeMediaVolume() { + enforceSelfOrSystemUI("disable the safe media volume"); synchronized (mSafeMediaVolumeState) { setSafeMediaVolumeEnabled(false); if (mPendingVolumeCommand != null) { @@ -4681,6 +4694,7 @@ public class AudioService extends IAudioService.Stub { pw.println("\nAudio routes:"); pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType)); pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName); + pw.print(" mVolumeController="); pw.println(mVolumeController); } // Inform AudioFlinger of our device's low RAM attribute @@ -4691,4 +4705,39 @@ public class AudioService extends IAudioService.Stub { Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status); } } + + private void enforceSelfOrSystemUI(String action) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE, + "Only SystemUI can " + action); + } + + @Override + public void setVolumeController(final IVolumeController controller) { + enforceSelfOrSystemUI("set the volume controller"); + + // return early if things are not actually changing + if (mVolumeController.isSameBinder(controller)) { + return; + } + + // dismiss the old volume controller + mVolumeController.postDismiss(); + if (controller != null) { + // we are about to register a new controller, listen for its death + try { + controller.asBinder().linkToDeath(new DeathRecipient() { + @Override + public void binderDied() { + if (mVolumeController.isSameBinder(controller)) { + Log.w(TAG, "Current remote volume controller died, unregistering"); + setVolumeController(null); + } + } + }, 0); + } catch (RemoteException e) { + // noop + } + } + mVolumeController.setController(controller); + } } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 2f08325..30de4f9 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -26,6 +26,7 @@ import android.media.IRemoteControlClient; import android.media.IRemoteControlDisplay; import android.media.IRemoteVolumeObserver; import android.media.IRingtonePlayer; +import android.media.IVolumeController; import android.media.Rating; import android.net.Uri; import android.view.KeyEvent; @@ -236,4 +237,10 @@ interface IAudioService { AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer); boolean isCameraSoundForced(); + + void setVolumeController(in IVolumeController controller); + + boolean isStreamAffectedByRingerMode(int streamType); + + void disableSafeMediaVolume(); } diff --git a/media/java/android/media/IVolumeController.aidl b/media/java/android/media/IVolumeController.aidl new file mode 100644 index 0000000..35d7708 --- /dev/null +++ b/media/java/android/media/IVolumeController.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + + +/** + * AIDL for the AudioService to report interesting events to a remote volume control dialog. + * @hide + */ +oneway interface IVolumeController { + void hasNewRemotePlaybackInfo(); + + void remoteVolumeChanged(int streamType, int flags); + + void remoteSliderVisibility(boolean visible); + + void displaySafeVolumeWarning(int flags); + + void volumeChanged(int streamType, int flags); + + void masterVolumeChanged(int flags); + + void masterMuteChanged(int flags); + + void setLayoutDirection(int layoutDirection); + + void dismiss(); +} diff --git a/media/java/android/media/VolumeController.java b/media/java/android/media/VolumeController.java index 2d12bf2..6b70cc3 100644 --- a/media/java/android/media/VolumeController.java +++ b/media/java/android/media/VolumeController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,120 @@ package android.media; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.Objects; + /** + * Wraps the remote volume controller interface as a convenience to audio service. * @hide */ -public interface VolumeController { +public class VolumeController { + private static final String TAG = "VolumeController"; + + private IVolumeController mController; + + public void setController(IVolumeController controller) { + mController = controller; + } + + public boolean isSameBinder(IVolumeController controller) { + return Objects.equals(asBinder(), binder(controller)); + } + + public IBinder asBinder() { + return binder(mController); + } + + private static IBinder binder(IVolumeController controller) { + return controller == null ? null : controller.asBinder(); + } + + @Override + public String toString() { + return "VolumeController(" + asBinder() + ")"; + } + + public void postHasNewRemotePlaybackInfo() { + if (mController == null) return; + try { + mController.hasNewRemotePlaybackInfo(); + } catch (RemoteException e) { + Log.w(TAG, "Error calling hasNewRemotePlaybackInfo", e); + } + } + + public void postRemoteVolumeChanged(int streamType, int flags) { + if (mController == null) return; + try { + mController.remoteVolumeChanged(streamType, flags); + } catch (RemoteException e) { + Log.w(TAG, "Error calling remoteVolumeChanged", e); + } + } + + public void postRemoteSliderVisibility(boolean visible) { + if (mController == null) return; + try { + mController.remoteSliderVisibility(visible); + } catch (RemoteException e) { + Log.w(TAG, "Error calling remoteSliderVisibility", e); + } + } + + public void postDisplaySafeVolumeWarning(int flags) { + if (mController == null) return; + try { + mController.displaySafeVolumeWarning(flags); + } catch (RemoteException e) { + Log.w(TAG, "Error calling displaySafeVolumeWarning", e); + } + } + + public void postVolumeChanged(int streamType, int flags) { + if (mController == null) return; + try { + mController.volumeChanged(streamType, flags); + } catch (RemoteException e) { + Log.w(TAG, "Error calling volumeChanged", e); + } + } + + public void postMasterVolumeChanged(int flags) { + if (mController == null) return; + try { + mController.masterVolumeChanged(flags); + } catch (RemoteException e) { + Log.w(TAG, "Error calling masterVolumeChanged", e); + } + } - public void postHasNewRemotePlaybackInfo(); + public void postMasterMuteChanged(int flags) { + if (mController == null) return; + try { + mController.masterMuteChanged(flags); + } catch (RemoteException e) { + Log.w(TAG, "Error calling masterMuteChanged", e); + } + } - public void postRemoteVolumeChanged(int streamType, int flags); + public void setLayoutDirection(int layoutDirection) { + if (mController == null) return; + try { + mController.setLayoutDirection(layoutDirection); + } catch (RemoteException e) { + Log.w(TAG, "Error calling setLayoutDirection", e); + } + } - public void postRemoteSliderVisibility(boolean visible); -} + public void postDismiss() { + if (mController == null) return; + try { + mController.dismiss(); + } catch (RemoteException e) { + Log.w(TAG, "Error calling dismiss", e); + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 217074f..d7ce255 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -47,6 +47,7 @@ public class SystemUIApplication extends Application { com.android.systemui.power.PowerUI.class, com.android.systemui.media.RingtonePlayer.class, com.android.systemui.settings.SettingsUI.class, + com.android.systemui.volume.VolumeUI.class, }; /** diff --git a/core/java/android/view/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java index 4730e59..8657e07 100644 --- a/core/java/android/view/VolumePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.view; +package com.android.systemui.volume; import com.android.internal.R; @@ -32,12 +32,18 @@ import android.media.AudioService; import android.media.AudioSystem; import android.media.RingtoneManager; import android.media.ToneGenerator; -import android.media.VolumeController; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.os.Vibrator; import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.widget.ImageView; import android.widget.SeekBar; @@ -46,27 +52,15 @@ import android.widget.SeekBar.OnSeekBarChangeListener; import java.util.HashMap; /** - * Handle the volume up and down keys. - * - * This code really should be moved elsewhere. - * - * Seriously, it really really should be moved elsewhere. This is used by - * android.media.AudioService, which actually runs in the system process, to - * show the volume dialog when the user changes the volume. What a mess. + * Handles the user interface for the volume keys. * * @hide */ -public class VolumePanel extends Handler implements VolumeController { +public class VolumePanel extends Handler { private static final String TAG = VolumePanel.class.getSimpleName(); private static boolean LOGD = false; - /** - * The delay before playing a sound. This small period exists so the user - * can press another key (non-volume keys, too) to have it NOT be audible. - * <p> - * PhoneWindow will implement this part. - */ - public static final int PLAY_SOUND_DELAY = 300; + private static final int PLAY_SOUND_DELAY = AudioService.PLAY_SOUND_DELAY; /** * The delay before vibrating. This small period exists so if the user is @@ -99,9 +93,8 @@ public class VolumePanel extends Handler implements VolumeController { private static final int STREAM_MASTER = -100; // Pseudo stream type for remote volume is defined in AudioService.STREAM_REMOTE_MUSIC - protected Context mContext; - private AudioManager mAudioManager; - protected AudioService mAudioService; + protected final Context mContext; + private final AudioManager mAudioManager; private boolean mRingIsSilent; private boolean mShowCombinedVolumes; private boolean mVoiceCapable; @@ -252,10 +245,9 @@ public class VolumePanel extends Handler implements VolumeController { } - public VolumePanel(Context context, AudioService volumeService) { + public VolumePanel(Context context) { mContext = context; mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - mAudioService = volumeService; // For now, only show master volume if master volume is supported final Resources res = context.getResources(); @@ -367,7 +359,7 @@ public class VolumePanel extends Handler implements VolumeController { if (streamType == STREAM_MASTER) { return mAudioManager.isMasterMute(); } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) { - return (mAudioService.getRemoteStreamVolume() <= 0); + return (mAudioManager.getRemoteStreamVolume() <= 0); } else { return mAudioManager.isStreamMute(streamType); } @@ -377,7 +369,7 @@ public class VolumePanel extends Handler implements VolumeController { if (streamType == STREAM_MASTER) { return mAudioManager.getMasterMaxVolume(); } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) { - return mAudioService.getRemoteStreamMaxVolume(); + return mAudioManager.getRemoteStreamMaxVolume(); } else { return mAudioManager.getStreamMaxVolume(streamType); } @@ -387,7 +379,7 @@ public class VolumePanel extends Handler implements VolumeController { if (streamType == STREAM_MASTER) { return mAudioManager.getMasterVolume(); } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) { - return mAudioService.getRemoteStreamVolume(); + return mAudioManager.getRemoteStreamVolume(); } else { return mAudioManager.getStreamVolume(streamType); } @@ -397,7 +389,7 @@ public class VolumePanel extends Handler implements VolumeController { if (streamType == STREAM_MASTER) { mAudioManager.setMasterVolume(index, flags); } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) { - mAudioService.setRemoteStreamVolume(index); + mAudioManager.setRemoteStreamVolume(index); } else { mAudioManager.setStreamVolume(streamType, index, flags); } @@ -531,7 +523,6 @@ public class VolumePanel extends Handler implements VolumeController { obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget(); } - @Override public void postRemoteVolumeChanged(int streamType, int flags) { if (hasMessages(MSG_REMOTE_VOLUME_CHANGED)) return; synchronized (this) { @@ -543,7 +534,6 @@ public class VolumePanel extends Handler implements VolumeController { obtainMessage(MSG_REMOTE_VOLUME_CHANGED, streamType, flags).sendToTarget(); } - @Override public void postRemoteSliderVisibility(boolean visible) { obtainMessage(MSG_SLIDER_VISIBILITY_CHANGED, AudioService.STREAM_REMOTE_MUSIC, visible ? 1 : 0).sendToTarget(); @@ -560,7 +550,6 @@ public class VolumePanel extends Handler implements VolumeController { * as a request to update the volume), the application will likely set a new volume. If the UI * is still up, we need to refresh the display to show this new value. */ - @Override public void postHasNewRemotePlaybackInfo() { if (hasMessages(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN)) return; // don't create or prevent resources to be freed, if they disappear, this update came too @@ -592,6 +581,11 @@ public class VolumePanel extends Handler implements VolumeController { obtainMessage(MSG_DISPLAY_SAFE_VOLUME_WARNING, flags, 0).sendToTarget(); } + public void postDismiss() { + removeMessages(MSG_TIMEOUT); + sendEmptyMessage(MSG_TIMEOUT); + } + /** * Override this if you have other work to do when the volume changes (for * example, vibrating, playing a sound, etc.). Make sure to call through to @@ -751,7 +745,7 @@ public class VolumePanel extends Handler implements VolumeController { // Do a little vibrate if applicable (only when going into vibrate mode) if ((streamType != AudioService.STREAM_REMOTE_MUSIC) && ((flags & AudioManager.FLAG_VIBRATE) != 0) && - mAudioService.isStreamAffectedByRingerMode(streamType) && + mAudioManager.isStreamAffectedByRingerMode(streamType) && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) { sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY); } @@ -874,7 +868,7 @@ public class VolumePanel extends Handler implements VolumeController { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mAudioService.disableSafeMediaVolume(); + mAudioManager.disableSafeMediaVolume(); } }) .setNegativeButton(com.android.internal.R.string.no, null) diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java new file mode 100644 index 0000000..9bd75b7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java @@ -0,0 +1,125 @@ +package com.android.systemui.volume; + +import android.content.Context; +import android.database.ContentObserver; +import android.media.AudioManager; +import android.media.IVolumeController; +import android.net.Uri; +import android.os.Handler; +import android.os.RemoteException; +import android.provider.Settings; +import android.util.Log; + +import com.android.systemui.SystemUI; + +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class VolumeUI extends SystemUI { + private static final String TAG = "VolumeUI"; + private static final String SETTING = "systemui_volume_controller"; // for testing + private static final Uri SETTING_URI = Settings.Global.getUriFor(SETTING); + private static final int DEFAULT = 1; // enabled by default + + private AudioManager mAudioManager; + private VolumeController mVolumeController; + + @Override + public void start() { + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + updateController(); + mContext.getContentResolver().registerContentObserver(SETTING_URI, false, mObserver); + } + + private void updateController() { + if (Settings.Global.getInt(mContext.getContentResolver(), SETTING, DEFAULT) != 0) { + if (mVolumeController == null) { + mVolumeController = new VolumeController(mContext); + } + Log.d(TAG, "Registering volume controller"); + mAudioManager.setVolumeController(mVolumeController); + } else { + Log.d(TAG, "Unregistering volume controller"); + mAudioManager.setVolumeController(null); + } + } + + private final ContentObserver mObserver = new ContentObserver(new Handler()) { + public void onChange(boolean selfChange, Uri uri) { + if (SETTING_URI.equals(uri)) { + updateController(); + } + } + }; + + /** For now, simply host an unmodified base volume panel in this process. */ + private final class VolumeController extends IVolumeController.Stub { + private final VolumePanel mPanel; + + public VolumeController(Context context) { + mPanel = new VolumePanel(context); + } + + @Override + public void hasNewRemotePlaybackInfo() throws RemoteException { + mPanel.postHasNewRemotePlaybackInfo(); + } + + @Override + public void remoteVolumeChanged(int streamType, int flags) + throws RemoteException { + mPanel.postRemoteVolumeChanged(streamType, flags); + } + + @Override + public void remoteSliderVisibility(boolean visible) + throws RemoteException { + mPanel.postRemoteSliderVisibility(visible); + } + + @Override + public void displaySafeVolumeWarning(int flags) throws RemoteException { + mPanel.postDisplaySafeVolumeWarning(flags); + } + + @Override + public void volumeChanged(int streamType, int flags) + throws RemoteException { + mPanel.postVolumeChanged(streamType, flags); + } + + @Override + public void masterVolumeChanged(int flags) throws RemoteException { + mPanel.postMasterVolumeChanged(flags); + } + + @Override + public void masterMuteChanged(int flags) throws RemoteException { + mPanel.postMasterMuteChanged(flags); + } + + @Override + public void setLayoutDirection(int layoutDirection) + throws RemoteException { + mPanel.setLayoutDirection(layoutDirection); + } + + @Override + public void dismiss() throws RemoteException { + mPanel.postDismiss(); + } + } +} |