1package com.android.systemui.volume;
2
3import android.content.Context;
4import android.content.res.Configuration;
5import android.database.ContentObserver;
6import android.media.AudioManager;
7import android.media.IRemoteVolumeController;
8import android.media.IVolumeController;
9import android.media.session.ISessionController;
10import android.media.session.MediaController;
11import android.media.session.MediaSessionManager;
12import android.net.Uri;
13import android.os.Bundle;
14import android.os.Handler;
15import android.os.RemoteException;
16import android.provider.Settings;
17import android.util.Log;
18
19import com.android.systemui.R;
20import com.android.systemui.SystemUI;
21import com.android.systemui.keyguard.KeyguardViewMediator;
22import com.android.systemui.statusbar.phone.PhoneStatusBar;
23import com.android.systemui.statusbar.policy.ZenModeController;
24import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
25
26import java.io.FileDescriptor;
27import 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
45public 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
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
78    protected void onConfigurationChanged(Configuration newConfig) {
79        super.onConfigurationChanged(newConfig);
80        if (mPanel != null) {
81            mPanel.onConfigurationChanged(newConfig);
82        }
83    }
84
85    @Override
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
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
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
153        public void displaySafeVolumeWarning(int flags) throws RemoteException {
154            mPanel.postDisplaySafeVolumeWarning(flags);
155        }
156
157        @Override
158        public void volumeChanged(int streamType, int flags)
159                throws RemoteException {
160            mPanel.postVolumeChanged(streamType, flags);
161        }
162
163        @Override
164        public void masterVolumeChanged(int flags) throws RemoteException {
165            mPanel.postMasterVolumeChanged(flags);
166        }
167
168        @Override
169        public void masterMuteChanged(int flags) throws RemoteException {
170            mPanel.postMasterMuteChanged(flags);
171        }
172
173        @Override
174        public void setLayoutDirection(int layoutDirection)
175                throws RemoteException {
176            mPanel.postLayoutDirection(layoutDirection);
177        }
178
179        @Override
180        public void dismiss() throws RemoteException {
181            dismissNow();
182        }
183
184        @Override
185        public ZenModeController getZenController() {
186            return mPanel.getZenController();
187        }
188
189        @Override
190        public void dispatchDemoCommand(String command, Bundle args) {
191            mPanel.dispatchDemoCommand(command, args);
192        }
193
194        @Override
195        public void dismissNow() {
196            mPanel.postDismiss(0);
197        }
198    }
199
200    private final class RemoteVolumeController extends IRemoteVolumeController.Stub {
201
202        @Override
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
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