summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--media/java/android/media/AudioManager.java78
-rw-r--r--media/java/android/media/AudioService.java71
-rw-r--r--media/java/android/media/IAudioService.aidl7
-rw-r--r--media/java/android/media/IVolumeController.aidl42
-rw-r--r--media/java/android/media/VolumeController.java118
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java1
-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.java125
9 files changed, 449 insertions, 50 deletions
diff --git a/Android.mk b/Android.mk
index 58509a7..2e78969 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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();
+ }
+ }
+}