1 package com.android.systemui.volume; 2 3 import android.content.Context; 4 import android.content.res.Configuration; 5 import android.database.ContentObserver; 6 import android.media.AudioManager; 7 import android.media.IRemoteVolumeController; 8 import android.media.IVolumeController; 9 import android.media.session.ISessionController; 10 import android.media.session.MediaController; 11 import android.media.session.MediaSessionManager; 12 import android.net.Uri; 13 import android.os.Bundle; 14 import android.os.Handler; 15 import android.os.RemoteException; 16 import android.provider.Settings; 17 import android.util.Log; 18 19 import com.android.systemui.R; 20 import com.android.systemui.SystemUI; 21 import com.android.systemui.keyguard.KeyguardViewMediator; 22 import com.android.systemui.statusbar.phone.PhoneStatusBar; 23 import com.android.systemui.statusbar.policy.ZenModeController; 24 import com.android.systemui.statusbar.policy.ZenModeControllerImpl; 25 26 import java.io.FileDescriptor; 27 import java.io.PrintWriter; 28 29 /* 30 * Copyright (C) 2014 The Android Open Source Project 31 * 32 * Licensed under the Apache License, Version 2.0 (the "License"); 33 * you may not use this file except in compliance with the License. 34 * You may obtain a copy of the License at 35 * 36 * http://www.apache.org/licenses/LICENSE-2.0 37 * 38 * Unless required by applicable law or agreed to in writing, software 39 * distributed under the License is distributed on an "AS IS" BASIS, 40 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 41 * See the License for the specific language governing permissions and 42 * limitations under the License. 43 */ 44 45 public class VolumeUI extends SystemUI { 46 private static final String TAG = "VolumeUI"; 47 private static final String SETTING = "systemui_volume_controller"; // for testing 48 private static final Uri SETTING_URI = Settings.Global.getUriFor(SETTING); 49 private static final int DEFAULT = 1; // enabled by default 50 51 private final Handler mHandler = new Handler(); 52 53 private boolean mEnabled; 54 private AudioManager mAudioManager; 55 private MediaSessionManager mMediaSessionManager; 56 private VolumeController mVolumeController; 57 private RemoteVolumeController mRemoteVolumeController; 58 59 private VolumePanel mPanel; 60 private int mDismissDelay; 61 62 @Override start()63 public void start() { 64 mEnabled = mContext.getResources().getBoolean(R.bool.enable_volume_ui); 65 if (!mEnabled) return; 66 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 67 mMediaSessionManager = (MediaSessionManager) mContext 68 .getSystemService(Context.MEDIA_SESSION_SERVICE); 69 initPanel(); 70 mVolumeController = new VolumeController(); 71 mRemoteVolumeController = new RemoteVolumeController(); 72 putComponent(VolumeComponent.class, mVolumeController); 73 updateController(); 74 mContext.getContentResolver().registerContentObserver(SETTING_URI, false, mObserver); 75 } 76 77 @Override onConfigurationChanged(Configuration newConfig)78 protected void onConfigurationChanged(Configuration newConfig) { 79 super.onConfigurationChanged(newConfig); 80 if (mPanel != null) { 81 mPanel.onConfigurationChanged(newConfig); 82 } 83 } 84 85 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)86 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 87 pw.print("mEnabled="); pw.println(mEnabled); 88 if (mPanel != null) { 89 mPanel.dump(fd, pw, args); 90 } 91 } 92 updateController()93 private void updateController() { 94 if (Settings.Global.getInt(mContext.getContentResolver(), SETTING, DEFAULT) != 0) { 95 Log.d(TAG, "Registering volume controller"); 96 mAudioManager.setVolumeController(mVolumeController); 97 mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController); 98 } else { 99 Log.d(TAG, "Unregistering volume controller"); 100 mAudioManager.setVolumeController(null); 101 mMediaSessionManager.setRemoteVolumeController(null); 102 } 103 } 104 initPanel()105 private void initPanel() { 106 mDismissDelay = mContext.getResources().getInteger(R.integer.volume_panel_dismiss_delay); 107 mPanel = new VolumePanel(mContext, new ZenModeControllerImpl(mContext, mHandler)); 108 mPanel.setCallback(new VolumePanel.Callback() { 109 @Override 110 public void onZenSettings() { 111 mHandler.removeCallbacks(mStartZenSettings); 112 mHandler.post(mStartZenSettings); 113 } 114 115 @Override 116 public void onInteraction() { 117 final KeyguardViewMediator kvm = getComponent(KeyguardViewMediator.class); 118 if (kvm != null) { 119 kvm.userActivity(); 120 } 121 } 122 123 @Override 124 public void onVisible(boolean visible) { 125 if (mAudioManager != null && mVolumeController != null) { 126 mAudioManager.notifyVolumeControllerVisible(mVolumeController, visible); 127 } 128 } 129 }); 130 } 131 132 private final ContentObserver mObserver = new ContentObserver(mHandler) { 133 public void onChange(boolean selfChange, Uri uri) { 134 if (SETTING_URI.equals(uri)) { 135 updateController(); 136 } 137 } 138 }; 139 140 private final Runnable mStartZenSettings = new Runnable() { 141 @Override 142 public void run() { 143 getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard( 144 ZenModePanel.ZEN_SETTINGS, true /* onlyProvisioned */, true /* dismissShade */); 145 mPanel.postDismiss(mDismissDelay); 146 } 147 }; 148 149 /** For now, simply host an unmodified base volume panel in this process. */ 150 private final class VolumeController extends IVolumeController.Stub implements VolumeComponent { 151 152 @Override displaySafeVolumeWarning(int flags)153 public void displaySafeVolumeWarning(int flags) throws RemoteException { 154 mPanel.postDisplaySafeVolumeWarning(flags); 155 } 156 157 @Override volumeChanged(int streamType, int flags)158 public void volumeChanged(int streamType, int flags) 159 throws RemoteException { 160 mPanel.postVolumeChanged(streamType, flags); 161 } 162 163 @Override masterVolumeChanged(int flags)164 public void masterVolumeChanged(int flags) throws RemoteException { 165 mPanel.postMasterVolumeChanged(flags); 166 } 167 168 @Override masterMuteChanged(int flags)169 public void masterMuteChanged(int flags) throws RemoteException { 170 mPanel.postMasterMuteChanged(flags); 171 } 172 173 @Override setLayoutDirection(int layoutDirection)174 public void setLayoutDirection(int layoutDirection) 175 throws RemoteException { 176 mPanel.postLayoutDirection(layoutDirection); 177 } 178 179 @Override dismiss()180 public void dismiss() throws RemoteException { 181 dismissNow(); 182 } 183 184 @Override getZenController()185 public ZenModeController getZenController() { 186 return mPanel.getZenController(); 187 } 188 189 @Override dispatchDemoCommand(String command, Bundle args)190 public void dispatchDemoCommand(String command, Bundle args) { 191 mPanel.dispatchDemoCommand(command, args); 192 } 193 194 @Override dismissNow()195 public void dismissNow() { 196 mPanel.postDismiss(0); 197 } 198 } 199 200 private final class RemoteVolumeController extends IRemoteVolumeController.Stub { 201 202 @Override remoteVolumeChanged(ISessionController binder, int flags)203 public void remoteVolumeChanged(ISessionController binder, int flags) 204 throws RemoteException { 205 MediaController controller = new MediaController(mContext, binder); 206 mPanel.postRemoteVolumeChanged(controller, flags); 207 } 208 209 @Override updateRemoteController(ISessionController session)210 public void updateRemoteController(ISessionController session) throws RemoteException { 211 mPanel.postRemoteSliderVisibility(session != null); 212 // TODO stash default session in case the slider can be opened other 213 // than by remoteVolumeChanged. 214 } 215 } 216 } 217