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